summaryrefslogtreecommitdiff
path: root/internal/layout
diff options
context:
space:
mode:
Diffstat (limited to 'internal/layout')
-rw-r--r--internal/layout/layout.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/internal/layout/layout.go b/internal/layout/layout.go
new file mode 100644
index 0000000..89e6848
--- /dev/null
+++ b/internal/layout/layout.go
@@ -0,0 +1,107 @@
+// Package layout defines Skiff's directory and dataset conventions in one
+// place. Nothing else in the codebase should hardcode a path.
+package layout
+
+import (
+ "fmt"
+ "path/filepath"
+)
+
+const (
+ DefaultHealthPort = 8080
+ DefaultHealthPath = "/healthz"
+ HealthTimeoutSecs = 10
+)
+
+// Config is Skiff's host-wide configuration. Every field has a sane FreeBSD
+// default; override via flags on the skiff binary if a host differs.
+type Config struct {
+ ZFSPool string // e.g. "zroot"
+ BaseDataset string // template jail root, cloned per app
+ ReposDir string // bare git repos live here
+ JailsMount string // parent mountpoint for per-app datasets
+ JailConfDir string // /etc/jail.conf.d
+ NginxConfDir string // nginx include dir regenerated on every deploy
+}
+
+func Default() Config {
+ return Config{
+ ZFSPool: "zroot/skiff",
+ BaseDataset: "zroot/skiff/base",
+ ReposDir: "/skiff/repos",
+ JailsMount: "/skiff/apps",
+ JailConfDir: "/etc/jail.conf.d",
+ NginxConfDir: "/usr/local/etc/nginx/skiff.d",
+ }
+}
+
+func (c Config) AppDataset(app string) string {
+ return fmt.Sprintf("%s/apps/%s", c.ZFSPool, app)
+}
+
+func (c Config) JailRoot(app string) string {
+ return filepath.Join(c.JailsMount, app)
+}
+
+func (c Config) RepoPath(app string) string {
+ return filepath.Join(c.ReposDir, app+".git")
+}
+
+func (c Config) JailConfPath(app string) string {
+ return filepath.Join(c.JailConfDir, app+".conf")
+}
+
+func (c Config) NginxConfPath(app string) string {
+ return filepath.Join(c.NginxConfDir, app+".conf")
+}
+
+// Everything below is Capistrano-style: each deploy gets its own immutable
+// releases/<sha> checkout (built in place, inside the jail's own dataset),
+// `current` is a symlink to whichever release is live, and data.db/env are
+// persistent siblings that outlive any single release.
+func (c Config) AppDir(app string) string {
+ return filepath.Join(c.JailRoot(app), "app")
+}
+
+func (c Config) ReleaseDir(app, sha string) string {
+ return filepath.Join(c.AppDir(app), "releases", sha)
+}
+
+func (c Config) CurrentRelease(app string) string {
+ return filepath.Join(c.AppDir(app), "current")
+}
+
+// ReleaseDirInJail is releases/<sha> as seen from inside the jail's own
+// chroot, not the host. The `current` symlink must be written with this
+// form as its target: it's dereferenced by the jail's rc.d script (execing
+// CurrentBin), where a host-absolute path like ReleaseDir's resolves
+// relative to the jail root instead and never exists.
+func (c Config) ReleaseDirInJail(sha string) string {
+ return filepath.Join("/app", "releases", sha)
+}
+
+// CurrentBin is the path the jail's rc.d script execs - must match
+// internal/tmpl/rc.d.tmpl's command_args.
+func (c Config) CurrentBin(app string) string {
+ return filepath.Join(c.CurrentRelease(app), "app")
+}
+
+func (c Config) MakefilePath(app, sha string) string {
+ return filepath.Join(c.ReleaseDir(app, sha), "Makefile")
+}
+
+func (c Config) DataDB(app string) string {
+ return filepath.Join(c.AppDir(app), "data.db")
+}
+
+func (c Config) EnvFile(app string) string {
+ return filepath.Join(c.AppDir(app), "env")
+}
+
+func (c Config) MetaPath(app string) string {
+ return filepath.Join(c.AppDir(app), "meta.json")
+}
+
+func (c Config) SnapshotName(app, sha string) string {
+ return fmt.Sprintf("%s@pre-%s", c.AppDataset(app), sha)
+}