pb volume
This commit is contained in:
16
README.md
16
README.md
@@ -6,7 +6,19 @@ A simple, rsync-based PocketBase deployment tool.
|
|||||||
|
|
||||||
### `init`
|
### `init`
|
||||||
|
|
||||||
Start a new PocketBase project (optionally provide a service name via `pb init <name>`)
|
Start a new PocketBase project (optionally provide a service name via `pb init <name>`) with a `pb.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[server]
|
||||||
|
ip = '127.0.0.1'
|
||||||
|
port = 8090
|
||||||
|
domain = 'example.com'
|
||||||
|
|
||||||
|
[pocketbase]
|
||||||
|
version = '0.35.1'
|
||||||
|
service = 'rusty-dusty'
|
||||||
|
volume = 'pb_data'
|
||||||
|
```
|
||||||
|
|
||||||
### `dev`
|
### `dev`
|
||||||
|
|
||||||
@@ -27,7 +39,7 @@ Provision a remote PocketBase server. This will:
|
|||||||
|
|
||||||
### `logs`
|
### `logs`
|
||||||
|
|
||||||
Connects to the configured server and streams `/root/pb/{service}/{service}.log` via `tail -n 100 -F`.
|
Streams the remote logs (`/root/pb/{service}/{service}.log`).
|
||||||
|
|
||||||
### `secrets`
|
### `secrets`
|
||||||
|
|
||||||
|
|||||||
49
main.go
49
main.go
@@ -15,6 +15,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -285,7 +286,10 @@ func runDev() error {
|
|||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPocketbaseVersion = "0.35.1"
|
const (
|
||||||
|
defaultPocketbaseVersion = "0.35.1"
|
||||||
|
defaultPocketbaseVolume = "pb_data"
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
@@ -297,6 +301,7 @@ func writePBConfig(path, serviceName string) error {
|
|||||||
const tmpl = `[pocketbase]
|
const tmpl = `[pocketbase]
|
||||||
version = "%s"
|
version = "%s"
|
||||||
service = "%s"
|
service = "%s"
|
||||||
|
volume = "%s"
|
||||||
|
|
||||||
[server]
|
[server]
|
||||||
ip = "127.0.0.1"
|
ip = "127.0.0.1"
|
||||||
@@ -304,7 +309,7 @@ port = 8090
|
|||||||
domain = "example.com"
|
domain = "example.com"
|
||||||
|
|
||||||
`
|
`
|
||||||
return os.WriteFile(path, []byte(fmt.Sprintf(tmpl, defaultPocketbaseVersion, serviceName)), 0o644)
|
return os.WriteFile(path, []byte(fmt.Sprintf(tmpl, defaultPocketbaseVersion, serviceName, defaultPocketbaseVolume)), 0o644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateServiceName() string {
|
func generateServiceName() string {
|
||||||
@@ -914,6 +919,7 @@ type serverConfig struct {
|
|||||||
type pocketBaseConfig struct {
|
type pocketBaseConfig struct {
|
||||||
Version string `toml:"version"`
|
Version string `toml:"version"`
|
||||||
ServiceName string `toml:"service"`
|
ServiceName string `toml:"service"`
|
||||||
|
Volume string `toml:"volume"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type deploymentContext struct {
|
type deploymentContext struct {
|
||||||
@@ -926,6 +932,8 @@ type deploymentContext struct {
|
|||||||
envFile string
|
envFile string
|
||||||
unitServiceDir string
|
unitServiceDir string
|
||||||
unitEnvFile string
|
unitEnvFile string
|
||||||
|
volume string
|
||||||
|
unitVolume string
|
||||||
configPath string
|
configPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,6 +978,12 @@ func buildDeploymentContext() (*deploymentContext, error) {
|
|||||||
envFile := renderServiceTemplate(defaultEnvFileTemplate, serviceName)
|
envFile := renderServiceTemplate(defaultEnvFileTemplate, serviceName)
|
||||||
unitServiceDir := renderServiceTemplate(defaultServiceDirTemplate, "%i")
|
unitServiceDir := renderServiceTemplate(defaultServiceDirTemplate, "%i")
|
||||||
unitEnvFile := renderServiceTemplate(defaultEnvFileTemplate, "%i")
|
unitEnvFile := renderServiceTemplate(defaultEnvFileTemplate, "%i")
|
||||||
|
volumeTemplate := cfg.PocketBase.Volume
|
||||||
|
if volumeTemplate == "" {
|
||||||
|
volumeTemplate = defaultPocketbaseVolume
|
||||||
|
}
|
||||||
|
volume := resolveVolumePath(volumeTemplate, serviceDir, serviceName)
|
||||||
|
unitVolume := resolveVolumePath(volumeTemplate, unitServiceDir, "%i")
|
||||||
|
|
||||||
return &deploymentContext{
|
return &deploymentContext{
|
||||||
serverIP: serverIP,
|
serverIP: serverIP,
|
||||||
@@ -981,6 +995,8 @@ func buildDeploymentContext() (*deploymentContext, error) {
|
|||||||
envFile: envFile,
|
envFile: envFile,
|
||||||
unitServiceDir: unitServiceDir,
|
unitServiceDir: unitServiceDir,
|
||||||
unitEnvFile: unitEnvFile,
|
unitEnvFile: unitEnvFile,
|
||||||
|
volume: volume,
|
||||||
|
unitVolume: unitVolume,
|
||||||
configPath: configPath,
|
configPath: configPath,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -1041,13 +1057,13 @@ func performSetup(ctx *deploymentContext) error {
|
|||||||
|
|
||||||
step++
|
step++
|
||||||
printStep(step, totalSetupSteps, "deploying PocketBase binary")
|
printStep(step, totalSetupSteps, "deploying PocketBase binary")
|
||||||
if err := runSSHCommand(ctx.serverIP, pocketbaseSetupScript(ctx.serviceDir, ctx.envFile, ctx.version, assetURL, ctx.port)); err != nil {
|
if err := runSSHCommand(ctx.serverIP, pocketbaseSetupScript(ctx.serviceDir, ctx.envFile, ctx.version, assetURL, ctx.volume, ctx.port)); err != nil {
|
||||||
return fmt.Errorf("PocketBase setup failed: %w", err)
|
return fmt.Errorf("PocketBase setup failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
step++
|
step++
|
||||||
printStep(step, totalSetupSteps, "configuring systemd service")
|
printStep(step, totalSetupSteps, "configuring systemd service")
|
||||||
if err := runSSHCommand(ctx.serverIP, systemdScript(ctx.unitServiceDir, ctx.unitEnvFile, ctx.serviceName)); err != nil {
|
if err := runSSHCommand(ctx.serverIP, systemdScript(ctx.unitServiceDir, ctx.unitEnvFile, ctx.unitVolume, ctx.serviceName)); err != nil {
|
||||||
return fmt.Errorf("systemd setup failed: %w", err)
|
return fmt.Errorf("systemd setup failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1402,6 +1418,17 @@ func renderServiceTemplate(tpl, serviceName string) string {
|
|||||||
return strings.ReplaceAll(tpl, "{service}", serviceName)
|
return strings.ReplaceAll(tpl, "{service}", serviceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveVolumePath(volumeTemplate, baseDir, serviceName string) string {
|
||||||
|
value := renderServiceTemplate(volumeTemplate, serviceName)
|
||||||
|
if value == "" {
|
||||||
|
return baseDir
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(value, "/") {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return path.Join(baseDir, value)
|
||||||
|
}
|
||||||
|
|
||||||
func translateMachineArch(value string) (string, error) {
|
func translateMachineArch(value string) (string, error) {
|
||||||
machine := strings.TrimSpace(strings.ToLower(value))
|
machine := strings.TrimSpace(strings.ToLower(value))
|
||||||
|
|
||||||
@@ -1496,7 +1523,7 @@ systemctl reload-or-restart caddy.service
|
|||||||
`, serviceName, domain, port)
|
`, serviceName, domain, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pocketbaseSetupScript(serviceDir, envFile, version, assetURL string, port int) string {
|
func pocketbaseSetupScript(serviceDir, envFile, version, assetURL, volume string, port int) string {
|
||||||
return fmt.Sprintf(`set -euo pipefail
|
return fmt.Sprintf(`set -euo pipefail
|
||||||
service_dir="%s"
|
service_dir="%s"
|
||||||
mkdir -p "$service_dir"
|
mkdir -p "$service_dir"
|
||||||
@@ -1511,19 +1538,23 @@ if [ ! -x "$binary" ]; then
|
|||||||
rm -f "$tmp"
|
rm -f "$tmp"
|
||||||
fi
|
fi
|
||||||
env_file="%s"
|
env_file="%s"
|
||||||
|
data_dir="%s"
|
||||||
current_port=""
|
current_port=""
|
||||||
if [ -f "$env_file" ]; then
|
if [ -f "$env_file" ]; then
|
||||||
current_port=$(grep '^PORT=' "$env_file" | head -n 1 | cut -d= -f2)
|
current_port=$(grep '^PORT=' "$env_file" | head -n 1 | cut -d= -f2)
|
||||||
fi
|
fi
|
||||||
|
if [ -n "$data_dir" ]; then
|
||||||
|
mkdir -p "$data_dir"
|
||||||
|
fi
|
||||||
if [ "$current_port" != "%d" ]; then
|
if [ "$current_port" != "%d" ]; then
|
||||||
cat <<'EOF' > "$env_file"
|
cat <<'EOF' > "$env_file"
|
||||||
PORT=%d
|
PORT=%d
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
`, serviceDir, serviceDir, assetURL, envFile, port, port)
|
`, serviceDir, serviceDir, assetURL, envFile, volume, port, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func systemdScript(serviceDir, envFile, serviceName string) string {
|
func systemdScript(serviceDir, envFile, volume, serviceName string) string {
|
||||||
return fmt.Sprintf(`set -euo pipefail
|
return fmt.Sprintf(`set -euo pipefail
|
||||||
cat <<'EOF' > /etc/systemd/system/pb@.service
|
cat <<'EOF' > /etc/systemd/system/pb@.service
|
||||||
[Unit]
|
[Unit]
|
||||||
@@ -1541,7 +1572,7 @@ StandardOutput = append:%s/%%i.log
|
|||||||
StandardError = append:%s/%%i.log
|
StandardError = append:%s/%%i.log
|
||||||
WorkingDirectory = %s
|
WorkingDirectory = %s
|
||||||
EnvironmentFile = %s
|
EnvironmentFile = %s
|
||||||
ExecStart = %s/pocketbase serve --http="127.0.0.1:${PORT}"
|
ExecStart = %s/pocketbase serve --dir=%s --http="127.0.0.1:${PORT}"
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy = multi-user.target
|
WantedBy = multi-user.target
|
||||||
@@ -1549,7 +1580,7 @@ EOF
|
|||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
systemctl --no-block enable --now pb@%s
|
systemctl --no-block enable --now pb@%s
|
||||||
systemctl --no-block restart pb@%s
|
systemctl --no-block restart pb@%s
|
||||||
`, serviceDir, serviceDir, serviceDir, envFile, serviceDir, serviceName, serviceName)
|
`, serviceDir, serviceDir, serviceDir, envFile, serviceDir, volume, serviceName, serviceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func systemdRestartScript(serviceName string) string {
|
func systemdRestartScript(serviceName string) string {
|
||||||
|
|||||||
Reference in New Issue
Block a user