Skip to content

AppEngine Datastore filesystem implementation for Afero

Notifications You must be signed in to change notification settings

CaptainCodeman/afero-datastore

Repository files navigation

Afero Datastore FileSystem

work in progress

AppEngine Datastore filesystem implementation for Afero

Allows the datastore to be treated as a filesystem by Go code which would, for instance, allow Hugo blog engine to run in the cloud - add a UI to edit the source files and regenerate the site when done, Afero also provides an Http filesystem which can be used to serve it.

Build flags are used to allow it to work with the google.golang.org/appengine/datastore package (for AppEngine Standard) or remotely via the newer cloud.google.com/go/datastore package (for AppEngine Flex, GCE or standalone.

Usage

Depending on whether you are using AppEngine Standard or Flex / GCS or some other platform, the constructor will vary (this is due to there being different datastore clients for the different platforms).

AppEngine Standard

Call NewFileSystem passing a context.Context sourced from the request (appengine.NewContext(r)) the namespace and kind to use for datastore entities and either dfs.Standard to use raw datastore calls or dfs.Memcache to use memcache. Note that due to AppEngine Standard restrictions, a filedsystem instance is only valid while associated with it's request.

fs := dfs.NewFileSystem(ctx, "captaincodeman", "drafts", dfs.Memcache)

AppEngine Flex / GCE

Create a datastore client with the google.golang.org/appengine/datastore package and pass to the NewFileSystem method along with a context.Context and the namespace and kind to use. Example using the default namespace and file entities stored as file in the datastore:

ctx := context.Background()
serviceAccount := option.WithServiceAccountFile("service-account.json")
client, _ := datastore.NewClient(ctx, "app-name", serviceAccount)

fs = NewFileSystem(client, "captaincodeman", "drafts")

Notes

The namespacing feature of datastore can be used in a similar way to having separate volumes.

Currently files are only saved to the datastore so they are limited to just under 1Mb each (usually plenty for a blog). in future this could be enhanced to use Google Cloud Storage for larger files.

To avoid too many datastore writes, the datastore entities are only written on close. Multiple filesystem sessions will therefore see inconsistent results. Access to files within the same fileysystem session will use the same file references for consistency with the same approach used as per the Afero memory file system (locks).

Testing

To test the standalone version, first download a service-account.json file for your project and set the project name in the file_system_standalone_test.go file, then run:

go test -v

To test AppEngine standard version, install the AppEngine SDK for Go and run:

goapp test -v

Known Issues

Afero isn't (yet) compatible with AppEngine Standard due to direct import of "syscall" but I have a fork that hides these behind build flags so that it can be used on the platform.

Some of the operations currently don't keep the session cache of files updated (but the tests pass and publishing via Hugo runs fine). Also, closed files should be removed to avoid excessive memory use (more critical if running on the low-memory AppEngine frontend instances).

Datastore is eventually consistent so some operations may not be immediately visible. Files are written on Close, so Directory operations will not always show newly created files (it typically works fine with Hugo).

Enhancements

  • Flags for test configuration (e.g. project name)
  • Fully clean-up tests and use more unique names for standalone namespace + entity to avoid conflicts
  • Improve usefulness of logging
  • Add storage-level compression (i.e. transparent to the caller)

About

AppEngine Datastore filesystem implementation for Afero

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages