refactor(main): Split HTTP handlers into separate functions

There is a new handler coming up to fix #102 and I want to avoid
falling into the classic Go trap of creating thousand-line functions.
This commit is contained in:
Vincent Ambo 2020-10-27 13:30:12 +01:00 committed by Vincent Ambo
parent 4ce32adfe8
commit 5ce745d104
2 changed files with 65 additions and 60 deletions

View file

@ -140,7 +140,7 @@ func pkgSourceFromEnv() (PkgSource, error) {
} }
if git := os.Getenv("NIXERY_PKGS_REPO"); git != "" { if git := os.Getenv("NIXERY_PKGS_REPO"); git != "" {
log.WithField("repo", git).Info("using NIx package set from git repository") log.WithField("repo", git).Info("using Nix package set from git repository")
return &GitSource{ return &GitSource{
repository: git, repository: git,

View file

@ -53,7 +53,7 @@ var version string = "devel"
// routes required for serving images, since pushing and other such // routes required for serving images, since pushing and other such
// functionality is not available. // functionality is not available.
var ( var (
manifestRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/([\w|\-|\.|\_]+)$`) manifestTagRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/([\w|\-|\.|\_]+)$`)
layerRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/blobs/sha256:(\w+)$`) layerRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/blobs/sha256:(\w+)$`)
) )
@ -112,32 +112,23 @@ type registryHandler struct {
state *builder.State state *builder.State
} }
func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Serve a manifest by tag, building it via Nix and populating caches
// Acknowledge that we speak V2 with an empty response // if necessary.
if r.RequestURI == "/v2/" { func (h *registryHandler) serveManifestTag(w http.ResponseWriter, r *http.Request, name string, tag string) {
return
}
// Serve the manifest (straight from Nix)
manifestMatches := manifestRegex.FindStringSubmatch(r.RequestURI)
if len(manifestMatches) == 3 {
imageName := manifestMatches[1]
imageTag := manifestMatches[2]
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"image": imageName, "image": name,
"tag": imageTag, "tag": tag,
}).Info("requesting image manifest") }).Info("requesting image manifest")
image := builder.ImageFromName(imageName, imageTag) image := builder.ImageFromName(name, tag)
buildResult, err := builder.BuildImage(r.Context(), h.state, &image) buildResult, err := builder.BuildImage(r.Context(), h.state, &image)
if err != nil { if err != nil {
writeError(w, 500, "UNKNOWN", "image build failure") writeError(w, 500, "UNKNOWN", "image build failure")
log.WithError(err).WithFields(log.Fields{ log.WithError(err).WithFields(log.Fields{
"image": imageName, "image": name,
"tag": imageTag, "tag": tag,
}).Error("failed to build image manifest") }).Error("failed to build image manifest")
return return
@ -150,8 +141,8 @@ func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
writeError(w, 404, "MANIFEST_UNKNOWN", s) writeError(w, 404, "MANIFEST_UNKNOWN", s)
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"image": imageName, "image": name,
"tag": imageTag, "tag": tag,
"packages": buildResult.Pkgs, "packages": buildResult.Pkgs,
}).Warn("could not find Nix packages") }).Warn("could not find Nix packages")
@ -163,15 +154,10 @@ func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
manifest, _ := json.Marshal(buildResult.Manifest) manifest, _ := json.Marshal(buildResult.Manifest)
w.Header().Add("Content-Type", manifestMediaType) w.Header().Add("Content-Type", manifestMediaType)
w.Write(manifest) w.Write(manifest)
return
} }
// Serve an image layer. For this we need to first ask Nix for // serveLayer serves an image layer from storage (if it exists).
// the manifest, then proceed to extract the correct layer from func (h *registryHandler) serveLayer(w http.ResponseWriter, r *http.Request, digest string) {
// it.
layerMatches := layerRegex.FindStringSubmatch(r.RequestURI)
if len(layerMatches) == 3 {
digest := layerMatches[2]
storage := h.state.Storage storage := h.state.Storage
err := storage.ServeLayer(digest, r, w) err := storage.ServeLayer(digest, r, w)
if err != nil { if err != nil {
@ -180,7 +166,26 @@ func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
"backend": storage.Name(), "backend": storage.Name(),
}).Error("failed to serve layer from storage backend") }).Error("failed to serve layer from storage backend")
} }
}
// ServeHTTP dispatches HTTP requests to the matching handlers.
func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Acknowledge that we speak V2 with an empty response
if r.RequestURI == "/v2/" {
return
}
// Build & serve a manifest by tag
manifestMatches := manifestTagRegex.FindStringSubmatch(r.RequestURI)
if len(manifestMatches) == 3 {
h.serveManifestTag(w, r, manifestMatches[1], manifestMatches[2])
return
}
// Serve an image layer
layerMatches := layerRegex.FindStringSubmatch(r.RequestURI)
if len(layerMatches) == 3 {
h.serveLayer(w, r, layerMatches[2])
return return
} }