-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5a9bf9b
commit 84ba26b
Showing
5 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
FROM golang:1.21.12 | ||
|
||
WORKDIR /usr/src/app | ||
|
||
# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change | ||
COPY go.mod ./ | ||
|
||
COPY . . | ||
RUN go build -v -o /usr/bin/k8s-keepalive ./... | ||
|
||
EXPOSE 5000 | ||
|
||
CMD ["/usr/bin/k8s-keepalive"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/mike-callahan/k8s-keepalive | ||
|
||
go 1.21.12 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"log" | ||
"net/http" | ||
"os" | ||
"os/signal" | ||
"syscall" | ||
"time" | ||
) | ||
|
||
func main() { | ||
log.Println("Starting keepalive service...") | ||
handler := http.HandlerFunc(HTTPProbe) | ||
server := &http.Server{ | ||
Addr: ":5000", | ||
Handler: handler, | ||
} | ||
|
||
go func() { | ||
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { | ||
log.Fatalf("HTTP server error: %v", err) | ||
} | ||
log.Println("Stopped serving new connections.") | ||
}() | ||
|
||
sigChan := make(chan os.Signal, 1) | ||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) | ||
<-sigChan | ||
|
||
shutdownCtx, shutdownRelease := context.WithTimeout(context.Background(), 10*time.Second) | ||
defer shutdownRelease() | ||
|
||
if err := server.Shutdown(shutdownCtx); err != nil { | ||
log.Fatalf("HTTP shutdown error: %v", err) | ||
} | ||
log.Println("Graceful shutdown complete.") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// Check if the status code passed by the user is valid | ||
func IsValidHTTPStatusCode(code int) bool { | ||
return code >= 100 && code <= 599 | ||
} | ||
|
||
// Respond to k8s health probes | ||
// Additional functionality of allowing user to pass arbitrary status codes for testing | ||
func HTTPProbe(w http.ResponseWriter, r *http.Request) { | ||
// Error if the request isn't Get or Post | ||
if r.Method != http.MethodGet && r.Method != http.MethodPost { | ||
w.WriteHeader(http.StatusBadRequest) | ||
fmt.Fprintln(w, "Only GET and POST requests are allowed") | ||
return | ||
} | ||
|
||
// Send 200 for / | ||
path := strings.TrimPrefix(r.URL.Path, "/") | ||
if path == "" || path == "healthz" { | ||
// Default response | ||
w.WriteHeader(http.StatusOK) | ||
fmt.Fprintln(w, "Hello! Pass a status code in the URL path (e.g., /200 or /404)") | ||
return | ||
} | ||
|
||
statusCode, _ := strconv.Atoi(path) | ||
_, err := strconv.Atoi(path) | ||
|
||
// Error if string can't be converted to integer | ||
if err != nil { | ||
w.WriteHeader(http.StatusBadRequest) | ||
fmt.Fprintln(w, "That is not a valid status code or integer.") | ||
return | ||
} | ||
|
||
// Error if integer is out of validity range | ||
err = nil | ||
if IsValidHTTPStatusCode(statusCode) == false { | ||
err = errors.New("That integer is not a valid status code") | ||
} | ||
|
||
if err != nil { | ||
w.WriteHeader(http.StatusBadRequest) | ||
fmt.Fprintln(w, fmt.Errorf("Error processing data: %w", err)) | ||
return | ||
} | ||
|
||
// Write value back to header and body | ||
w.WriteHeader(statusCode) | ||
fmt.Fprintf(w, "%d", statusCode) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
) | ||
|
||
func TestHTTPProbe(t *testing.T) { | ||
t.Run("Return default status", func(t *testing.T) { | ||
request, _ := http.NewRequest(http.MethodGet, "/", nil) | ||
response := httptest.NewRecorder() | ||
|
||
HTTPProbe(response, request) | ||
|
||
got := response.Result().StatusCode | ||
want := 200 | ||
|
||
if got != want { | ||
t.Errorf("got %q, want %q", got, want) | ||
} | ||
|
||
}) | ||
t.Run("Return status 200", func(t *testing.T) { | ||
request, _ := http.NewRequest(http.MethodGet, "/200", nil) | ||
response := httptest.NewRecorder() | ||
|
||
HTTPProbe(response, request) | ||
|
||
got := response.Result().StatusCode | ||
want := 200 | ||
|
||
if got != want { | ||
t.Errorf("got %q, want %q", got, want) | ||
} | ||
|
||
}) | ||
|
||
t.Run("Return status 404", func(t *testing.T) { | ||
request, _ := http.NewRequest(http.MethodGet, "/404", nil) | ||
response := httptest.NewRecorder() | ||
|
||
HTTPProbe(response, request) | ||
|
||
got := response.Result().StatusCode | ||
want := 404 | ||
|
||
if got != want { | ||
t.Errorf("got %q, want %q", got, want) | ||
} | ||
|
||
}) | ||
|
||
t.Run("Return status non-status", func(t *testing.T) { | ||
request, _ := http.NewRequest(http.MethodGet, "/asdf", nil) | ||
response := httptest.NewRecorder() | ||
|
||
HTTPProbe(response, request) | ||
|
||
got := response.Result().StatusCode | ||
want := 400 | ||
|
||
if got != want { | ||
t.Errorf("got %d, want %d", got, want) | ||
} | ||
|
||
}) | ||
|
||
t.Run("PATCH method", func(t *testing.T) { | ||
request, _ := http.NewRequest(http.MethodPatch, "/asdf", nil) | ||
response := httptest.NewRecorder() | ||
|
||
HTTPProbe(response, request) | ||
|
||
got := response.Result().StatusCode | ||
want := 400 | ||
|
||
if got != want { | ||
t.Errorf("got %d, want %d", got, want) | ||
} | ||
|
||
}) | ||
} |