From e5bb2fc887f8d4e7216a1dfcbfa81baac2b09cfd Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Mon, 28 Oct 2019 17:52:41 +0100 Subject: feat(server): Implement initial filesystem storage backend This allows users to store and serve layers from a local filesystem path. --- tools/nixery/server/storage/filesystem.go | 68 +++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tools/nixery/server/storage/filesystem.go (limited to 'tools') diff --git a/tools/nixery/server/storage/filesystem.go b/tools/nixery/server/storage/filesystem.go new file mode 100644 index 0000000000..ef763da67f --- /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 +} -- cgit 1.4.1