about summary refs log tree commit diff
path: root/tools/nixery/main.go
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@google.com>2020-10-27T12·30+0100
committerVincent Ambo <mail@tazj.in>2020-10-27T13·03+0100
commit5ce745d104e82d836967e3bd9fd7af9602e76114 (patch)
tree7460ec21a8eca168e70f5bc804c5ca89fba7411c /tools/nixery/main.go
parent4ce32adfe8aff1189e42a8a375782c9ea86a0b79 (diff)
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.
Diffstat (limited to 'tools/nixery/main.go')
-rw-r--r--tools/nixery/main.go117
1 files changed, 61 insertions, 56 deletions
diff --git a/tools/nixery/main.go b/tools/nixery/main.go
index 6cad93740978..92c602b1f79f 100644
--- a/tools/nixery/main.go
+++ b/tools/nixery/main.go
@@ -53,8 +53,8 @@ var version string = "devel"
 // routes required for serving images, since pushing and other such
 // functionality is not available.
 var (
-	manifestRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/([\w|\-|\.|\_]+)$`)
-	layerRegex    = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/blobs/sha256:(\w+)$`)
+	manifestTagRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/([\w|\-|\.|\_]+)$`)
+	layerRegex       = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/blobs/sha256:(\w+)$`)
 )
 
 // Downloads the popularity information for the package set from the
@@ -112,75 +112,80 @@ type registryHandler struct {
 	state *builder.State
 }
 
-func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	// Acknowledge that we speak V2 with an empty response
-	if r.RequestURI == "/v2/" {
-		return
-	}
+// Serve a manifest by tag, building it via Nix and populating caches
+// if necessary.
+func (h *registryHandler) serveManifestTag(w http.ResponseWriter, r *http.Request, name string, tag string) {
+	log.WithFields(log.Fields{
+		"image": name,
+		"tag":   tag,
+	}).Info("requesting image manifest")
 
-	// Serve the manifest (straight from Nix)
-	manifestMatches := manifestRegex.FindStringSubmatch(r.RequestURI)
-	if len(manifestMatches) == 3 {
-		imageName := manifestMatches[1]
-		imageTag := manifestMatches[2]
+	image := builder.ImageFromName(name, tag)
+	buildResult, err := builder.BuildImage(r.Context(), h.state, &image)
 
-		log.WithFields(log.Fields{
-			"image": imageName,
-			"tag":   imageTag,
-		}).Info("requesting image manifest")
+	if err != nil {
+		writeError(w, 500, "UNKNOWN", "image build failure")
 
-		image := builder.ImageFromName(imageName, imageTag)
-		buildResult, err := builder.BuildImage(r.Context(), h.state, &image)
+		log.WithError(err).WithFields(log.Fields{
+			"image": name,
+			"tag":   tag,
+		}).Error("failed to build image manifest")
 
-		if err != nil {
-			writeError(w, 500, "UNKNOWN", "image build failure")
+		return
+	}
 
-			log.WithError(err).WithFields(log.Fields{
-				"image": imageName,
-				"tag":   imageTag,
-			}).Error("failed to build image manifest")
+	// Some error types have special handling, which is applied
+	// here.
+	if buildResult.Error == "not_found" {
+		s := fmt.Sprintf("Could not find Nix packages: %v", buildResult.Pkgs)
+		writeError(w, 404, "MANIFEST_UNKNOWN", s)
 
-			return
-		}
+		log.WithFields(log.Fields{
+			"image":    name,
+			"tag":      tag,
+			"packages": buildResult.Pkgs,
+		}).Warn("could not find Nix packages")
 
-		// Some error types have special handling, which is applied
-		// here.
-		if buildResult.Error == "not_found" {
-			s := fmt.Sprintf("Could not find Nix packages: %v", buildResult.Pkgs)
-			writeError(w, 404, "MANIFEST_UNKNOWN", s)
+		return
+	}
 
-			log.WithFields(log.Fields{
-				"image":    imageName,
-				"tag":      imageTag,
-				"packages": buildResult.Pkgs,
-			}).Warn("could not find Nix packages")
+	// This marshaling error is ignored because we know that this
+	// field represents valid JSON data.
+	manifest, _ := json.Marshal(buildResult.Manifest)
+	w.Header().Add("Content-Type", manifestMediaType)
+	w.Write(manifest)
+}
 
-			return
-		}
+// serveLayer serves an image layer from storage (if it exists).
+func (h *registryHandler) serveLayer(w http.ResponseWriter, r *http.Request, digest string) {
+	storage := h.state.Storage
+	err := storage.ServeLayer(digest, r, w)
+	if err != nil {
+		log.WithError(err).WithFields(log.Fields{
+			"layer":   digest,
+			"backend": storage.Name(),
+		}).Error("failed to serve layer from storage backend")
+	}
+}
 
-		// This marshaling error is ignored because we know that this
-		// field represents valid JSON data.
-		manifest, _ := json.Marshal(buildResult.Manifest)
-		w.Header().Add("Content-Type", manifestMediaType)
-		w.Write(manifest)
+// 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
 	}
 
-	// Serve an image layer. For this we need to first ask Nix for
-	// the manifest, then proceed to extract the correct layer from
-	// it.
+	// 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 {
-		digest := layerMatches[2]
-		storage := h.state.Storage
-		err := storage.ServeLayer(digest, r, w)
-		if err != nil {
-			log.WithError(err).WithFields(log.Fields{
-				"layer":   digest,
-				"backend": storage.Name(),
-			}).Error("failed to serve layer from storage backend")
-		}
-
+		h.serveLayer(w, r, layerMatches[2])
 		return
 	}