about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVincent Ambo <tazjin@google.com>2019-10-28T16·52+0100
committerVincent Ambo <github@tazj.in>2019-10-28T21·31+0100
commite5bb2fc887f8d4e7216a1dfcbfa81baac2b09cfd (patch)
treec2c779354e9b8171ce9685a54156ba5dde0cd28b
parente8fd6b67348610ff7bbd4585036567b9e56945b7 (diff)
feat(server): Implement initial filesystem storage backend
This allows users to store and serve layers from a local filesystem
path.
-rw-r--r--tools/nixery/server/storage/filesystem.go68
1 files changed, 68 insertions, 0 deletions
diff --git a/tools/nixery/server/storage/filesystem.go b/tools/nixery/server/storage/filesystem.go
new file mode 100644
index 000000000000..ef763da67f14
--- /dev/null
+++ b/tools/nixery/server/storage/filesystem.go
@@ -0,0 +1,68 @@
+// Filesystem storage backend for Nixery.
+package storage
+
+import (
+	"fmt"
+	"io"
+	"net/http"
+	"os"
+	"path"
+
+	log "github.com/sirupsen/logrus"
+)
+
+type FSBackend struct {
+	path string
+}
+
+func NewFSBackend(p string) (*FSBackend, error) {
+	p = path.Clean(p)
+	err := os.MkdirAll(p, 0755)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create storage dir: %s", err)
+	}
+
+	return &FSBackend{p}, nil
+}
+
+func (b *FSBackend) Name() string {
+	return fmt.Sprintf("Filesystem (%s)", b.path)
+}
+
+func (b *FSBackend) Persist(key string, f func(io.Writer) (string, int64, error)) (string, int64, error) {
+	full := path.Join(b.path, key)
+	dir := path.Dir(full)
+	err := os.MkdirAll(dir, 0755)
+	if err != nil {
+		log.WithError(err).WithField("path", dir).Error("failed to create storage directory")
+		return "", 0, err
+	}
+
+	file, err := os.OpenFile(full, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
+	if err != nil {
+		log.WithError(err).WithField("file", full).Error("failed to write file")
+		return "", 0, err
+	}
+	defer file.Close()
+
+	return f(file)
+}
+
+func (b *FSBackend) Fetch(key string) (io.ReadCloser, error) {
+	full := path.Join(b.path, key)
+	return os.Open(full)
+}
+
+func (b *FSBackend) Move(old, new string) error {
+	return os.Rename(path.Join(b.path, old), path.Join(b.path, new))
+}
+
+func (b *FSBackend) ServeLayer(digest string, w http.ResponseWriter) error {
+	// http.Serve* functions attempt to be a lot more clever than
+	// I want, but I also would prefer to avoid implementing error
+	// translation myself - thus a fake request is created here.
+	req := http.Request{Method: "GET"}
+	http.ServeFile(w, &req, path.Join(b.path, "sha256:"+digest))
+
+	return nil
+}