Skip to content

Commit

Permalink
frontend proof of concept
Browse files Browse the repository at this point in the history
  • Loading branch information
kayra1 committed Jun 3, 2024
1 parent 516e435 commit b025a4a
Show file tree
Hide file tree
Showing 25 changed files with 774 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-rock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
docker run -d -p 3000:3000 --name gocert gocert:latest
- name: Load config
run: |
docker exec gocert /bin/pebble mkdir /etc/config
docker exec gocert /usr/bin/pebble mkdir /etc/config
docker cp key.pem gocert:/etc/config/key.pem
docker cp cert.pem gocert:/etc/config/cert.pem
docker cp config.yaml gocert:/etc/config/config.yaml
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/go-lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ jobs:
name: frontend-static-files
path: ui/out
- name: golangci-lint
uses: golangci/golangci-lint-action@v5
uses: golangci/golangci-lint-action@v6
with:
version: v1.54
2 changes: 1 addition & 1 deletion .github/workflows/publish-rock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@v3.1.0
uses: docker/login-action@v3.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.22.1

require (
github.com/mattn/go-sqlite3 v1.14.22
github.com/prometheus/client_golang v1.19.0
github.com/prometheus/client_golang v1.19.1
gopkg.in/yaml.v3 v3.0.1
)

Expand All @@ -15,6 +15,6 @@ require (
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/sys v0.17.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
Expand All @@ -23,8 +23,8 @@ github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
25 changes: 5 additions & 20 deletions internal/api/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,38 +27,23 @@ func NewGoCertRouter(env *Environment) http.Handler {
apiV1Router.HandleFunc("POST /certificate_requests/{id}/certificate/reject", RejectCertificate(env))
apiV1Router.HandleFunc("DELETE /certificate_requests/{id}/certificate", DeleteCertificate(env))

metricsHandler := metrics.NewPrometheusMetricsHandler()
m := metrics.NewMetricsSubsystem(env.DB)
frontendHandler := newFrontendFileServer()

router := http.NewServeMux()
router.HandleFunc("/status", HealthCheck)
router.Handle("/metrics", metricsHandler)
router.Handle("/metrics", m.Handler)
router.Handle("/api/v1/", http.StripPrefix("/api/v1", apiV1Router))
router.Handle("/", frontendHandler)

ctx := Context{}
ctx := middlewareContext{metrics: m}
middleware := createMiddlewareStack(
Metrics(&ctx),
Logging(&ctx),
metricsMiddleware(&ctx),
loggingMiddleware(&ctx),
)
return middleware(router)
}

// createMiddlewareStack chains given middleware for the server.
// Each middleware functions calls next.ServeHTTP in order to resume the chain of execution.
// The order these functions are given to createMiddlewareStack matters.
// The functions will run the code before next.ServeHTTP in order.
// The functions will run the code after next.ServeHTTP in reverse order.
func createMiddlewareStack(middleware ...Middleware) Middleware {
return func(next http.Handler) http.Handler {
for i := len(middleware) - 1; i >= 0; i-- {
mw := middleware[i]
next = mw(next)
}
return next
}
}

// newFrontendFileServer uses the embedded ui output files as the base for a file server
func newFrontendFileServer() http.Handler {
frontendFS, err := fs.Sub(ui.FrontendFS, "out")
Expand Down
63 changes: 44 additions & 19 deletions internal/api/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,75 @@ package server
import (
"log"
"net/http"

"github.com/canonical/gocert/internal/metrics"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

type Middleware func(http.Handler) http.Handler
type middleware func(http.Handler) http.Handler

// The Context type helps middleware pass along information through the chain.
type Context struct {
// The middlewareContext type helps middleware receive and pass along information through the middleware chain.
type middlewareContext struct {
responseStatusCode int
metrics *metrics.PrometheusMetrics
}

// The ResponseWriterCloner struct implements the http.ResponseWriter class, and copies the status
// code of the response for the middleware to be able to read the responses.
type ResponseWriterCloner struct {
// The responseWriterCloner struct wraps the http.ResponseWriter struct, and extracts the status
// code of the response writer for the middleware to read
type responseWriterCloner struct {
http.ResponseWriter
statusCode int
}

// NewResponseWriter returns a new ResponseWriterCloner struct
func NewResponseWriter(w http.ResponseWriter) *ResponseWriterCloner {
return &ResponseWriterCloner{w, http.StatusOK}
// newResponseWriter returns a new ResponseWriterCloner struct
// it returns http.StatusOK by default because the http.ResponseWriter defaults to that header
// if the WriteHeader() function is never called.
func newResponseWriter(w http.ResponseWriter) *responseWriterCloner {
return &responseWriterCloner{w, http.StatusOK}
}

// WriteHeader duplicates the status code into the cloner struct for reading
func (rwc *ResponseWriterCloner) WriteHeader(code int) {
// WriteHeader overrides the ResponseWriter method to duplicate the status code into the wrapper struct
func (rwc *responseWriterCloner) WriteHeader(code int) {
rwc.statusCode = code
rwc.ResponseWriter.WriteHeader(code)
}

// createMiddlewareStack chains the given middleware functions to wrap the api.
// Each middleware functions calls next.ServeHTTP in order to resume the chain of execution.
// The order the middleware functions are given to createMiddlewareStack matters.
// Any code before next.ServeHTTP is called is executed in the given middleware's order.
// Any code after next.ServeHTTP is called is executed in the given middleware's reverse order.
func createMiddlewareStack(middleware ...middleware) middleware {
return func(next http.Handler) http.Handler {
for i := len(middleware) - 1; i >= 0; i-- {
mw := middleware[i]
next = mw(next)
}
return next
}
}

// The Metrics middleware captures any request relevant to a metric and records it for prometheus.
func Metrics(ctx *Context) Middleware {
func metricsMiddleware(ctx *middlewareContext) middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)
if ctx.responseStatusCode != 200 {
return
}
base := promhttp.InstrumentHandlerCounter(
&ctx.metrics.RequestsTotal,
promhttp.InstrumentHandlerDuration(
&ctx.metrics.RequestsDuration,
next,
),
)
base.ServeHTTP(w, r)
})
}
}

// The logging middleware captures any http request coming through, and logs it.
func Logging(ctx *Context) Middleware {
// The Logging middleware captures any http request coming through and the response status code, and logs it.
func loggingMiddleware(ctx *middlewareContext) middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
clonedWwriter := NewResponseWriter(w)
clonedWwriter := newResponseWriter(w)
next.ServeHTTP(w, r)
log.Println(r.Method, r.URL.Path, clonedWwriter.statusCode, http.StatusText(clonedWwriter.statusCode))
ctx.responseStatusCode = clonedWwriter.statusCode
Expand Down
1 change: 0 additions & 1 deletion internal/api/middleware_test.go

This file was deleted.

2 changes: 2 additions & 0 deletions internal/certdb/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func ValidateCertificateRequest(csr string) error {
if err != nil {
return err
}
// TODO: We should validate the actual certificate request parameters here too. (Has the required fields etc)
return nil
}

Expand All @@ -40,6 +41,7 @@ func ValidateCertificate(cert string) error {
if err != nil {
return err
}
// TODO: We should validate the actual certificate parameters here too. (Has the required fields etc)
return nil
}

Expand Down
Loading

0 comments on commit b025a4a

Please sign in to comment.