Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
gpanders committed Nov 18, 2024
0 parents commit db9d140
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 0 deletions.
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM golang:1.23 AS build

WORKDIR /usr/src/app

COPY go.mod ./
RUN go mod download && go mod verify

COPY main.go index.html .
RUN CGO_ENABLED=0 go build -v -o /usr/local/bin/app ./...

FROM debian:bookworm-slim
COPY --from=build /usr/local/bin/app /usr/local/bin/

CMD ["/usr/local/bin/app", "-addr", "0.0.0.0"]
13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright (c) 2024 Cloudflare, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Cloudflare Container Example

This repo contains a simple example application which can be run in Cloudflare's
container runtime.

The example app serves a single HTML page with an incrementing visit counter and a
toggleable health status. The health status can be modified by sending a POST
request to `/health` with the `status` query parameter set to either `healthy`
or `unhealthy`. The health status can be queried by sending a GET request to
`/health`: if the application is healthy it will return an empty response with
a 200 status code; otherwise, it will send an empty response with a 503 status
code.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/cloudflare/hello-world-container-image

go 1.23.2
24 changes: 24 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
<title>Cloudflare Container Example</title>
</head>
<body>
<h1>Cloudflare Container Example</h1>
<p>
This page is rendered and served by an application running on Cloudflare's container platform.
It has been visited <strong>{{ .Visits }}</strong> time(s).
</p>

<form method="POST" action="/health?h={{ if .Healthy }}false{{ else }}true{{ end }}">
<p>
Health status:
{{ if .Healthy }}
<span style="color:green;">HEALTHY</span>
{{ else }}
<span style="color:red;">UNHEALTHY</span>
{{ end }}
</p>
<button type="submit">Toggle health status</button>
</form>
</body>
84 changes: 84 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package main

import (
_ "embed"
"flag"
"fmt"
"html/template"
"log"
"net/http"
)

//go:embed index.html
var content string
var templates = template.Must(template.New("index.html").Parse(content))

type State struct {
Visits int
Healthy bool
}

func index(s *State) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := templates.Execute(w, s); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}

s.Visits += 1
}
}

func health(s *State) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
if s.Healthy {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusServiceUnavailable)
}
case http.MethodPost:
if err := r.ParseForm(); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

params := r.URL.Query()
h, ok := params["h"]
if !ok {
w.WriteHeader(http.StatusNotModified)
return
}

if len(h) != 1 || (h[0] != "true" && h[0] != "false") {
w.WriteHeader(http.StatusBadRequest)
return
}

healthy := h[0] == "true"
if healthy == s.Healthy {
w.WriteHeader(http.StatusNotModified)
return
}

s.Healthy = healthy
http.Redirect(w, r, "/", http.StatusSeeOther)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
}

func main() {
addr := flag.String("addr", "127.0.0.1", "address to listen on")
port := flag.Int("port", 8000, "TCP port to listen on")

flag.Parse()

s := State{Healthy: true}
http.HandleFunc("/", index(&s))
http.HandleFunc("/health", health(&s))

log.Printf("Listening on %s:%d...", *addr, *port)
log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", *addr, *port), nil))
}

0 comments on commit db9d140

Please sign in to comment.