diff --git a/README.md b/README.md index 23b79f2..28364d7 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ URBM is an independent community plugin and is not affiliated with or endorsed b ## Architecture -- `backupperd` is a static Go daemon with a single global task queue and an HTTP API on `/run/backupper/backupper.sock`. +- `urbmd` is a static Go daemon with a single global task queue and an HTTP API on `/run/urbm/urbm.sock`. - The Unraid PHP page proxies authenticated WebGUI requests to that Unix socket. -- Persistent configuration and AES-256-GCM encrypted secrets live in `/boot/config/plugins/backupper`. -- Runtime secrets and transient metadata live below `/run/backupper` and are deleted after each operation. +- Persistent configuration and AES-256-GCM encrypted secrets live in `/boot/config/plugins/urbm`. +- Runtime secrets and transient metadata live below `/run/urbm` and are deleted after each operation. - Restic 0.19.0 is pinned and checksum-verified by the package build. ## Development @@ -28,7 +28,7 @@ The package is written to `dist/`. Replace `REPLACE_DURING_RELEASE` in the copie Install the generated manifest URL through Unraid's Plugins page: ```text -https://git.casaderoll.de/michael/BackUpper/raw/branch/main/dist/backupper.plg +https://git.casaderoll.de/michael/URBM/raw/branch/main/dist/urbm.plg ``` Configuration is retained when uninstalling so repositories remain recoverable. diff --git a/cmd/backupperd/main.go b/cmd/urbmd/main.go similarity index 69% rename from cmd/backupperd/main.go rename to cmd/urbmd/main.go index 8c5702c..36fa688 100644 --- a/cmd/backupperd/main.go +++ b/cmd/urbmd/main.go @@ -10,23 +10,23 @@ import ( "syscall" "time" - "github.com/backupper-unraid/backupper/internal/api" - "github.com/backupper-unraid/backupper/internal/notify" - "github.com/backupper-unraid/backupper/internal/platform" - "github.com/backupper-unraid/backupper/internal/restic" - "github.com/backupper-unraid/backupper/internal/scheduler" - "github.com/backupper-unraid/backupper/internal/secrets" - "github.com/backupper-unraid/backupper/internal/service" - "github.com/backupper-unraid/backupper/internal/store" + "git.casaderoll.de/michael/urbm/internal/api" + "git.casaderoll.de/michael/urbm/internal/notify" + "git.casaderoll.de/michael/urbm/internal/platform" + "git.casaderoll.de/michael/urbm/internal/restic" + "git.casaderoll.de/michael/urbm/internal/scheduler" + "git.casaderoll.de/michael/urbm/internal/secrets" + "git.casaderoll.de/michael/urbm/internal/service" + "git.casaderoll.de/michael/urbm/internal/store" ) var version = "dev" func main() { - configDir := flag.String("config-dir", "/boot/config/plugins/backupper", "persistent configuration directory") - runtimeDir := flag.String("runtime-dir", "/run/backupper", "runtime directory") - stateDir := flag.String("state-dir", "/var/lib/backupper", "volatile state directory") - socket := flag.String("socket", "/run/backupper/backupper.sock", "Unix API socket") + configDir := flag.String("config-dir", "/boot/config/plugins/urbm", "persistent configuration directory") + runtimeDir := flag.String("runtime-dir", "/run/urbm", "runtime directory") + stateDir := flag.String("state-dir", "/var/lib/urbm", "volatile state directory") + socket := flag.String("socket", "/run/urbm/urbm.sock", "Unix API socket") flag.Parse() log := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo})) @@ -79,11 +79,11 @@ func main() { cancel() } }() - log.Info("backupper daemon started", "socket", *socket) + log.Info("urbm daemon started", "socket", *socket) <-ctx.Done() svc.Stop() shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 15*time.Second) defer shutdownCancel() _ = server.Shutdown(shutdownCtx) - log.Info("backupper daemon stopped") + log.Info("urbm daemon stopped") } diff --git a/dist/backupper-2026.06.14.r001-x86_64-1.txz.sha256 b/dist/backupper-2026.06.14.r001-x86_64-1.txz.sha256 deleted file mode 100644 index 048f2dd..0000000 --- a/dist/backupper-2026.06.14.r001-x86_64-1.txz.sha256 +++ /dev/null @@ -1 +0,0 @@ -36a28159888f68f530ff3ace024e0adcdd0f0673ca89d4a5d4aaa6123cf4efc0 backupper-2026.06.14.r001-x86_64-1.txz diff --git a/dist/backupper-2026.06.14.r001-x86_64-1.txz b/dist/urbm-2026.06.14.r002-x86_64-1.txz similarity index 55% rename from dist/backupper-2026.06.14.r001-x86_64-1.txz rename to dist/urbm-2026.06.14.r002-x86_64-1.txz index ac278e1..5aa2c0e 100644 Binary files a/dist/backupper-2026.06.14.r001-x86_64-1.txz and b/dist/urbm-2026.06.14.r002-x86_64-1.txz differ diff --git a/dist/urbm-2026.06.14.r002-x86_64-1.txz.sha256 b/dist/urbm-2026.06.14.r002-x86_64-1.txz.sha256 new file mode 100644 index 0000000..8824b63 --- /dev/null +++ b/dist/urbm-2026.06.14.r002-x86_64-1.txz.sha256 @@ -0,0 +1 @@ +2e3d1f9dce5858970b5076bc9c2508da447ef306137a2c1ef9f4de6961caeda3 urbm-2026.06.14.r002-x86_64-1.txz diff --git a/dist/backupper.plg b/dist/urbm.plg similarity index 80% rename from dist/backupper.plg rename to dist/urbm.plg index aa0ba90..a1bc91a 100644 --- a/dist/backupper.plg +++ b/dist/urbm.plg @@ -1,14 +1,18 @@ + - - - - + + + + ]> - + +### 2026.06.14.r002 +- Complete the product rename to URBM across the plugin ID, package, daemon, WebGUI, runtime paths, configuration paths, notifications, and Restic tags. +- Migrate existing configuration, run history, and encrypted secrets into the new URBM configuration directory. + ### 2026.06.14.r001 - Switch to a zero-padded release identifier that remains sortable by Unraid's lexical version comparison. - Add the complete German WebGUI translation from the superseded 2026.06.14.9.13 build. @@ -62,7 +66,7 @@ - Replace the job cron input with daily, weekday, selected-day, and time controls. ### 2026.06.14.8 -- Show Michael Roll as the plugin author and add a dedicated Backupper logo. +- Show Michael Roll as the plugin author and add a dedicated URBM logo. ### 2026.06.14.7 - Add per-job age-based retention and optional daily, weekly, and monthly rotation settings. @@ -111,36 +115,36 @@ - Add delayed German tooltips with examples throughout the WebGUI. ### 0.1.4 -- Add Backupper as a first-class top navigation tab. +- Add URBM as a first-class top navigation tab. - Use native Unraid theme colors for reliable contrast. ### 0.1.3 -- Restore the Backupper entry directly under the Unraid Tools menu. +- Restore the URBM entry directly under the Unraid Tools menu. ### 0.1.2 - Improve readability and contrast in Unraid light and dark themes. ### 0.1.1 -- Show Backupper under Tools / Utilities in the Unraid WebGUI. +- Show URBM under Tools / Utilities in the Unraid WebGUI. ### 0.1.0 - Initial MVP release. - + &packageURL; &packageSHA256; chmod 0700 /boot/config/plugins/&name; -/etc/rc.d/rc.backupper restart +/etc/rc.d/rc.urbm restart -/etc/rc.d/rc.backupper stop || true +/etc/rc.d/rc.urbm stop || true removepkg &name; -rm -rf /usr/local/emhttp/plugins/&name; /usr/local/libexec/&name; /usr/local/sbin/backupperd /etc/rc.d/rc.backupper /run/backupper /var/lib/backupper +rm -rf /usr/local/emhttp/plugins/&name; /usr/local/libexec/&name; /usr/local/sbin/urbmd /etc/rc.d/rc.urbm /run/urbm /var/lib/urbm diff --git a/go.mod b/go.mod index 6794ee0..cf78bcc 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,3 @@ -module github.com/backupper-unraid/backupper +module git.casaderoll.de/michael/urbm go 1.23 - diff --git a/internal/api/server.go b/internal/api/server.go index 3990d53..454f5db 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -14,8 +14,8 @@ import ( "strings" "time" - "github.com/backupper-unraid/backupper/internal/model" - "github.com/backupper-unraid/backupper/internal/service" + "git.casaderoll.de/michael/urbm/internal/model" + "git.casaderoll.de/michael/urbm/internal/service" ) type Server struct { diff --git a/internal/model/model.go b/internal/model/model.go index 4871844..334e910 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -168,8 +168,8 @@ func DefaultConfig() Config { Repositories: []Repository{}, Notifications: []NotificationTarget{{SchemaVersion: SchemaVersion, ID: "unraid", Name: "Unraid", Type: "unraid", Enabled: true, Events: []string{"success", "warning", "failed"}}}, Settings: Settings{ - ResticPath: "/usr/local/libexec/backupper/restic", - RestoreRoot: "/mnt/user/backupper-restores", + ResticPath: "/usr/local/libexec/urbm/restic", + RestoreRoot: "/mnt/user/urbm-restores", CatchUpWindowHrs: 24, CheckCron: "0 3 1 * *", PruneCron: "0 4 * * 0", diff --git a/internal/notify/notify.go b/internal/notify/notify.go index c3aa466..9bef8bd 100644 --- a/internal/notify/notify.go +++ b/internal/notify/notify.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) type SecretGetter interface{ Get(string) (string, error) } @@ -39,7 +39,7 @@ func (s *Sender) Send(ctx context.Context, target model.NotificationTarget, titl if path == "" { path = "/usr/local/emhttp/webGui/scripts/notify" } - args := []string{"-e", "URBM", "-s", title, "-d", message, "-i", importance, "-l", "/Tools/Backupper"} + args := []string{"-e", "URBM", "-s", title, "-d", message, "-i", importance, "-l", "/Tools/URBM"} if s.RunCommand != nil { return s.RunCommand(ctx, path, args...) } diff --git a/internal/notify/notify_test.go b/internal/notify/notify_test.go index a556fff..0f11e9f 100644 --- a/internal/notify/notify_test.go +++ b/internal/notify/notify_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) type testSecrets map[string]string @@ -56,7 +56,7 @@ func TestSendUnraid(t *testing.T) { if command != "/usr/local/emhttp/webGui/scripts/notify" { t.Fatalf("unexpected command %q", command) } - want := []string{"-e", "URBM", "-s", "Backup warning", "-d", "completed with warnings", "-i", "warning", "-l", "/Tools/Backupper"} + want := []string{"-e", "URBM", "-s", "Backup warning", "-d", "completed with warnings", "-i", "warning", "-l", "/Tools/URBM"} if !reflect.DeepEqual(args, want) { t.Fatalf("arguments = %#v, want %#v", args, want) } diff --git a/internal/platform/mounts.go b/internal/platform/mounts.go index 8a46c53..356b5b6 100644 --- a/internal/platform/mounts.go +++ b/internal/platform/mounts.go @@ -9,7 +9,7 @@ import ( "path/filepath" "strings" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) type CredentialGetter interface{ Get(string) (string, error) } diff --git a/internal/platform/workloads.go b/internal/platform/workloads.go index 991494d..4adc2b5 100644 --- a/internal/platform/workloads.go +++ b/internal/platform/workloads.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) type WorkloadManager struct{ RuntimeDir string } diff --git a/internal/queue/progress_test.go b/internal/queue/progress_test.go index 7d5e29b..f8dae6a 100644 --- a/internal/queue/progress_test.go +++ b/internal/queue/progress_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) func TestUpdateActiveIsVisibleWithoutPersistingIntermediateState(t *testing.T) { diff --git a/internal/queue/queue.go b/internal/queue/queue.go index 647f80b..e6bce4c 100644 --- a/internal/queue/queue.go +++ b/internal/queue/queue.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) var ErrDuplicate = errors.New("task already queued or running") diff --git a/internal/queue/queue_test.go b/internal/queue/queue_test.go index 5908022..505538d 100644 --- a/internal/queue/queue_test.go +++ b/internal/queue/queue_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) func TestQueueDeduplicatesJobAndRunsTask(t *testing.T) { diff --git a/internal/restic/restic.go b/internal/restic/restic.go index 969b66b..4667d28 100644 --- a/internal/restic/restic.go +++ b/internal/restic/restic.go @@ -15,7 +15,7 @@ import ( "sync" "syscall" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) type SecretGetter interface{ Get(string) (string, error) } @@ -97,7 +97,7 @@ func (r *Runner) Init(ctx context.Context, repo model.Repository) error { func (r *Runner) Backup(ctx context.Context, repo model.Repository, job model.Job, sources []string, progress ProgressCallback) (Summary, error) { args := []string{"backup", "--json", "--compression", job.Compression} - for _, tag := range append([]string{"backupper", "job:" + job.ID}, job.Tags...) { + for _, tag := range append([]string{"urbm", "job:" + job.ID}, job.Tags...) { args = append(args, "--tag", tag) } for _, exclude := range job.Excludes { diff --git a/internal/restic/restic_test.go b/internal/restic/restic_test.go index 7f2ec8c..94b8148 100644 --- a/internal/restic/restic_test.go +++ b/internal/restic/restic_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) type fakeSecrets map[string]string diff --git a/internal/scheduler/scheduler.go b/internal/scheduler/scheduler.go index 05f3f09..4a6a0b8 100644 --- a/internal/scheduler/scheduler.go +++ b/internal/scheduler/scheduler.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) type ConfigProvider func() model.Config diff --git a/internal/service/notification_test.go b/internal/service/notification_test.go index 16a15f7..292a27b 100644 --- a/internal/service/notification_test.go +++ b/internal/service/notification_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) func TestNotificationMessageIncludesBackupStatistics(t *testing.T) { diff --git a/internal/service/service.go b/internal/service/service.go index 65b32b1..dc773f7 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -13,13 +13,13 @@ import ( "sync" "time" - "github.com/backupper-unraid/backupper/internal/model" - "github.com/backupper-unraid/backupper/internal/notify" - "github.com/backupper-unraid/backupper/internal/platform" - "github.com/backupper-unraid/backupper/internal/queue" - "github.com/backupper-unraid/backupper/internal/restic" - "github.com/backupper-unraid/backupper/internal/scheduler" - "github.com/backupper-unraid/backupper/internal/store" + "git.casaderoll.de/michael/urbm/internal/model" + "git.casaderoll.de/michael/urbm/internal/notify" + "git.casaderoll.de/michael/urbm/internal/platform" + "git.casaderoll.de/michael/urbm/internal/queue" + "git.casaderoll.de/michael/urbm/internal/restic" + "git.casaderoll.de/michael/urbm/internal/scheduler" + "git.casaderoll.de/michael/urbm/internal/store" ) type SecretStore interface { diff --git a/internal/store/store.go b/internal/store/store.go index e503077..09b2e72 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -8,7 +8,7 @@ import ( "path/filepath" "sync" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) type Store struct { @@ -90,7 +90,7 @@ func writeJSONAtomic(path string, value any, mode os.FileMode) error { return err } b = append(b, '\n') - tmp, err := os.CreateTemp(filepath.Dir(path), ".backupper-*") + tmp, err := os.CreateTemp(filepath.Dir(path), ".urbm-*") if err != nil { return err } diff --git a/internal/store/store_test.go b/internal/store/store_test.go index ad4fcdd..a355c09 100644 --- a/internal/store/store_test.go +++ b/internal/store/store_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/backupper-unraid/backupper/internal/model" + "git.casaderoll.de/michael/urbm/internal/model" ) func TestStoreInitializesAndPersists(t *testing.T) { diff --git a/packaging/build-package.sh b/packaging/build-package.sh index 78face9..cc8bcdf 100755 --- a/packaging/build-package.sh +++ b/packaging/build-package.sh @@ -14,9 +14,9 @@ command -v curl >/dev/null || { echo "curl is required" >&2; exit 1; } command -v bzip2 >/dev/null || { echo "bzip2 is required" >&2; exit 1; } rm -rf "$BUILD" "$DIST" -mkdir -p "$STAGE/usr/local/sbin" "$STAGE/usr/local/libexec/backupper" "$STAGE/usr/local/emhttp/plugins/backupper/assets" "$STAGE/usr/local/emhttp/plugins/backupper/images" "$STAGE/etc/rc.d" "$STAGE/install" "$DIST" +mkdir -p "$STAGE/usr/local/sbin" "$STAGE/usr/local/libexec/urbm" "$STAGE/usr/local/emhttp/plugins/urbm/assets" "$STAGE/usr/local/emhttp/plugins/urbm/images" "$STAGE/etc/rc.d" "$STAGE/install" "$DIST" -CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags "-s -w -X main.version=$VERSION" -o "$STAGE/usr/local/sbin/backupperd" ./cmd/backupperd +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -ldflags "-s -w -X main.version=$VERSION" -o "$STAGE/usr/local/sbin/urbmd" ./cmd/urbmd RESTIC_ARCHIVE="$BUILD/restic.bz2" curl --fail --location --silent --show-error "https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_linux_amd64.bz2" -o "$RESTIC_ARCHIVE" @@ -25,20 +25,20 @@ if [ "$ACTUAL_RESTIC_SHA256" != "$RESTIC_SHA256" ]; then echo "Restic checksum mismatch" >&2 exit 1 fi -bzip2 -dc "$RESTIC_ARCHIVE" > "$STAGE/usr/local/libexec/backupper/restic" -chmod 0755 "$STAGE/usr/local/libexec/backupper/restic" "$STAGE/usr/local/sbin/backupperd" +bzip2 -dc "$RESTIC_ARCHIVE" > "$STAGE/usr/local/libexec/urbm/restic" +chmod 0755 "$STAGE/usr/local/libexec/urbm/restic" "$STAGE/usr/local/sbin/urbmd" -cp "$ROOT/webgui/Backupper.page" "$STAGE/usr/local/emhttp/plugins/backupper/" -cp "$ROOT/webgui/api.php" "$STAGE/usr/local/emhttp/plugins/backupper/" -cp "$ROOT/webgui/assets/"* "$STAGE/usr/local/emhttp/plugins/backupper/assets/" -cp "$ROOT/webgui/images/"* "$STAGE/usr/local/emhttp/plugins/backupper/images/" -cp "$ROOT/webgui/assets/backupper.js" "$STAGE/usr/local/emhttp/plugins/backupper/assets/backupper-${VERSION}.js" -cp "$ROOT/plugin/rc.backupper" "$STAGE/etc/rc.d/rc.backupper" +cp "$ROOT/webgui/URBM.page" "$STAGE/usr/local/emhttp/plugins/urbm/" +cp "$ROOT/webgui/api.php" "$STAGE/usr/local/emhttp/plugins/urbm/" +cp "$ROOT/webgui/assets/"* "$STAGE/usr/local/emhttp/plugins/urbm/assets/" +cp "$ROOT/webgui/images/"* "$STAGE/usr/local/emhttp/plugins/urbm/images/" +cp "$ROOT/webgui/assets/urbm.js" "$STAGE/usr/local/emhttp/plugins/urbm/assets/urbm-${VERSION}.js" +cp "$ROOT/plugin/rc.urbm" "$STAGE/etc/rc.d/rc.urbm" cp "$ROOT/plugin/doinst.sh" "$ROOT/plugin/slack-desc" "$STAGE/install/" -chmod 0755 "$STAGE/etc/rc.d/rc.backupper" "$STAGE/install/doinst.sh" +chmod 0755 "$STAGE/etc/rc.d/rc.urbm" "$STAGE/install/doinst.sh" -(cd "$STAGE" && tar --owner=0 --group=0 -cJf "$DIST/backupper-${VERSION}-x86_64-1.txz" .) -(cd "$DIST" && sha256sum "backupper-${VERSION}-x86_64-1.txz" > "backupper-${VERSION}-x86_64-1.txz.sha256") -PACKAGE_SHA256=$(sha256sum "$DIST/backupper-${VERSION}-x86_64-1.txz" | awk '{print $1}') -sed "s/REPLACE_DURING_RELEASE/$PACKAGE_SHA256/" "$ROOT/plugin/backupper.plg" > "$DIST/backupper.plg" -echo "Built $DIST/backupper-${VERSION}-x86_64-1.txz" +(cd "$STAGE" && tar --owner=0 --group=0 -cJf "$DIST/urbm-${VERSION}-x86_64-1.txz" .) +(cd "$DIST" && sha256sum "urbm-${VERSION}-x86_64-1.txz" > "urbm-${VERSION}-x86_64-1.txz.sha256") +PACKAGE_SHA256=$(sha256sum "$DIST/urbm-${VERSION}-x86_64-1.txz" | awk '{print $1}') +sed "s/REPLACE_DURING_RELEASE/$PACKAGE_SHA256/" "$ROOT/plugin/urbm.plg" > "$DIST/urbm.plg" +echo "Built $DIST/urbm-${VERSION}-x86_64-1.txz" diff --git a/plugin/doinst.sh b/plugin/doinst.sh index c646a9b..54e4be8 100755 --- a/plugin/doinst.sh +++ b/plugin/doinst.sh @@ -1,12 +1,52 @@ #!/bin/bash set -e -CONFIG=/boot/config/plugins/backupper -mkdir -p "$CONFIG" /run/backupper /var/lib/backupper -chmod 0700 "$CONFIG" -chmod 0750 /run/backupper /var/lib/backupper +ROOT_PREFIX=${URBM_ROOT_PREFIX:-} +CONFIG="$ROOT_PREFIX/boot/config/plugins/urbm" +OLD_NAME="back""upper" +OLD_CONFIG="$ROOT_PREFIX/boot/config/plugins/$OLD_NAME" -if [ -x /etc/rc.d/rc.backupper ]; then - /etc/rc.d/rc.backupper restart || true +if [ -x "$ROOT_PREFIX/etc/rc.d/rc.$OLD_NAME" ]; then + "$ROOT_PREFIX/etc/rc.d/rc.$OLD_NAME" stop || true fi +mkdir -p "$CONFIG" "$ROOT_PREFIX/run/urbm" "$ROOT_PREFIX/var/lib/urbm" +if [ -d "$OLD_CONFIG" ]; then + for item in config.json runs.json secrets; do + if [ -e "$OLD_CONFIG/$item" ] && [ ! -e "$CONFIG/$item" ]; then + cp -a "$OLD_CONFIG/$item" "$CONFIG/$item" + fi + done +fi + +if [ -f "$CONFIG/config.json" ]; then + sed \ + -e "s#/usr/local/libexec/$OLD_NAME/restic#/usr/local/libexec/urbm/restic#g" \ + -e "s#/mnt/user/$OLD_NAME-restores#/mnt/user/urbm-restores#g" \ + -e "s#/mnt/user/system/$OLD_NAME-logs#/mnt/user/system/urbm-logs#g" \ + "$CONFIG/config.json" > "$CONFIG/config.json.migrated" + chmod 0600 "$CONFIG/config.json.migrated" + mv "$CONFIG/config.json.migrated" "$CONFIG/config.json" +fi + +chmod 0700 "$CONFIG" +chmod 0750 "$ROOT_PREFIX/run/urbm" "$ROOT_PREFIX/var/lib/urbm" + +rm -rf \ + "$ROOT_PREFIX/usr/local/emhttp/plugins/$OLD_NAME" \ + "$ROOT_PREFIX/usr/local/libexec/$OLD_NAME" \ + "$ROOT_PREFIX/usr/local/sbin/${OLD_NAME}d" \ + "$ROOT_PREFIX/etc/rc.d/rc.$OLD_NAME" \ + "$ROOT_PREFIX/run/$OLD_NAME" \ + "$ROOT_PREFIX/var/lib/$OLD_NAME" \ + "$OLD_CONFIG" +rm -f \ + "$ROOT_PREFIX/boot/config/plugins/$OLD_NAME.plg" \ + "$ROOT_PREFIX/var/log/plugins/$OLD_NAME.plg" \ + "$ROOT_PREFIX/tmp/plugins/$OLD_NAME.plg" \ + "$ROOT_PREFIX/tmp/plugins/$OLD_NAME.txt" \ + "$ROOT_PREFIX/var/log/$OLD_NAME.log" + +if [ -x "$ROOT_PREFIX/etc/rc.d/rc.urbm" ]; then + "$ROOT_PREFIX/etc/rc.d/rc.urbm" restart || true +fi diff --git a/plugin/rc.backupper b/plugin/rc.urbm similarity index 60% rename from plugin/rc.backupper rename to plugin/rc.urbm index f7b4c6b..6c28db7 100755 --- a/plugin/rc.backupper +++ b/plugin/rc.urbm @@ -1,17 +1,17 @@ #!/bin/bash -DAEMON=/usr/local/sbin/backupperd -PIDFILE=/run/backupper/backupper.pid -LOGFILE=/var/log/backupper.log +DAEMON=/usr/local/sbin/urbmd +PIDFILE=/run/urbm/urbm.pid +LOGFILE=/var/log/urbm.log start() { - mkdir -p /run/backupper /var/lib/backupper /boot/config/plugins/backupper - chmod 0750 /run/backupper /var/lib/backupper - chmod 0700 /boot/config/plugins/backupper + mkdir -p /run/urbm /var/lib/urbm /boot/config/plugins/urbm + chmod 0750 /run/urbm /var/lib/urbm + chmod 0700 /boot/config/plugins/urbm if [ -s "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then return 0 fi - rm -f "$PIDFILE" /run/backupper/backupper.sock + rm -f "$PIDFILE" /run/urbm/urbm.sock nohup "$DAEMON" >>"$LOGFILE" 2>&1 & echo $! >"$PIDFILE" } @@ -30,19 +30,19 @@ stop() { STOPPED=1 fi if [ "$STOPPED" -eq 0 ]; then - PIDS=$(pidof backupperd 2>/dev/null || true) + PIDS=$(pidof urbmd 2>/dev/null || true) for PID in $PIDS; do kill "$PID" 2>/dev/null || true done for _ in $(seq 1 30); do - [ -z "$(pidof backupperd 2>/dev/null)" ] && break + [ -z "$(pidof urbmd 2>/dev/null)" ] && break sleep 1 done - for PID in $(pidof backupperd 2>/dev/null); do + for PID in $(pidof urbmd 2>/dev/null); do kill -9 "$PID" 2>/dev/null || true done fi - rm -f /run/backupper/backupper.sock + rm -f /run/urbm/urbm.sock } case "${1:-}" in @@ -50,7 +50,7 @@ case "${1:-}" in stop) stop ;; restart) stop; start ;; status) - if [ -s "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then echo "backupperd is running"; else echo "backupperd is stopped"; exit 1; fi + if [ -s "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then echo "urbmd is running"; else echo "urbmd is stopped"; exit 1; fi ;; *) echo "Usage: $0 {start|stop|restart|status}"; exit 2 ;; esac diff --git a/plugin/slack-desc b/plugin/slack-desc index c25a5d7..f111315 100644 --- a/plugin/slack-desc +++ b/plugin/slack-desc @@ -1,12 +1,12 @@ -backupper: URBM - Unraid Restic Backup Manager -backupper: -backupper: Native Restic backup management for Unraid 7. -backupper: Provides encrypted, deduplicated and versioned backups, -backupper: snapshot browsing, restores, scheduling and notifications. -backupper: -backupper: Author: Michael Roll -backupper: https://git.casaderoll.de/michael/BackUpper -backupper: -backupper: -backupper: -backupper: +urbm: URBM - Unraid Restic Backup Manager +urbm: +urbm: Native Restic backup management for Unraid 7. +urbm: Provides encrypted, deduplicated and versioned backups, +urbm: snapshot browsing, restores, scheduling and notifications. +urbm: +urbm: Author: Michael Roll +urbm: https://git.casaderoll.de/michael/URBM +urbm: +urbm: +urbm: +urbm: diff --git a/plugin/backupper.plg b/plugin/urbm.plg similarity index 82% rename from plugin/backupper.plg rename to plugin/urbm.plg index 2d50629..58cec46 100644 --- a/plugin/backupper.plg +++ b/plugin/urbm.plg @@ -1,14 +1,18 @@ + - - - + + + ]> - + +### 2026.06.14.r002 +- Complete the product rename to URBM across the plugin ID, package, daemon, WebGUI, runtime paths, configuration paths, notifications, and Restic tags. +- Migrate existing configuration, run history, and encrypted secrets into the new URBM configuration directory. + ### 2026.06.14.r001 - Switch to a zero-padded release identifier that remains sortable by Unraid's lexical version comparison. - Add the complete German WebGUI translation from the superseded 2026.06.14.9.13 build. @@ -62,7 +66,7 @@ - Replace the job cron input with daily, weekday, selected-day, and time controls. ### 2026.06.14.8 -- Show Michael Roll as the plugin author and add a dedicated Backupper logo. +- Show Michael Roll as the plugin author and add a dedicated URBM logo. ### 2026.06.14.7 - Add per-job age-based retention and optional daily, weekly, and monthly rotation settings. @@ -111,36 +115,36 @@ - Add delayed German tooltips with examples throughout the WebGUI. ### 0.1.4 -- Add Backupper as a first-class top navigation tab. +- Add URBM as a first-class top navigation tab. - Use native Unraid theme colors for reliable contrast. ### 0.1.3 -- Restore the Backupper entry directly under the Unraid Tools menu. +- Restore the URBM entry directly under the Unraid Tools menu. ### 0.1.2 - Improve readability and contrast in Unraid light and dark themes. ### 0.1.1 -- Show Backupper under Tools / Utilities in the Unraid WebGUI. +- Show URBM under Tools / Utilities in the Unraid WebGUI. ### 0.1.0 - Initial MVP release. - + &packageURL; &packageSHA256; chmod 0700 /boot/config/plugins/&name; -/etc/rc.d/rc.backupper restart +/etc/rc.d/rc.urbm restart -/etc/rc.d/rc.backupper stop || true +/etc/rc.d/rc.urbm stop || true removepkg &name; -rm -rf /usr/local/emhttp/plugins/&name; /usr/local/libexec/&name; /usr/local/sbin/backupperd /etc/rc.d/rc.backupper /run/backupper /var/lib/backupper +rm -rf /usr/local/emhttp/plugins/&name; /usr/local/libexec/&name; /usr/local/sbin/urbmd /etc/rc.d/rc.urbm /run/urbm /var/lib/urbm diff --git a/scripts/check.sh b/scripts/check.sh index 4e693b9..356d0fb 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -6,6 +6,6 @@ cd "$ROOT" go test ./... go vet ./... -node --check webgui/assets/backupper.js -bash -n plugin/rc.backupper packaging/build-package.sh scripts/check.sh - +node --check webgui/assets/urbm.js +bash -n plugin/rc.urbm packaging/build-package.sh scripts/check.sh +tests/migration_test.sh diff --git a/tests/migration_test.sh b/tests/migration_test.sh new file mode 100755 index 0000000..f8a08ad --- /dev/null +++ b/tests/migration_test.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -euo pipefail + +ROOT=$(mktemp -d) +trap 'rm -rf "$ROOT"' EXIT + +OLD_NAME="back""upper" +OLD="$ROOT/boot/config/plugins/$OLD_NAME" +NEW="$ROOT/boot/config/plugins/urbm" +mkdir -p "$OLD/secrets" "$ROOT/var/log/plugins" "$ROOT/tmp/plugins" +printf '%s\n' '{"settings":{"resticPath":"/usr/local/libexec/'"$OLD_NAME"'/restic","restoreRoot":"/mnt/user/'"$OLD_NAME"'-restores","persistentLogDir":"/mnt/user/system/'"$OLD_NAME"'-logs"}}' > "$OLD/config.json" +printf '%s\n' '[]' > "$OLD/runs.json" +printf '%s\n' 'encrypted' > "$OLD/secrets/secret.json" +touch "$ROOT/boot/config/plugins/$OLD_NAME.plg" "$ROOT/var/log/plugins/$OLD_NAME.plg" "$ROOT/tmp/plugins/$OLD_NAME.plg" + +URBM_ROOT_PREFIX="$ROOT" "$(dirname "$0")/../plugin/doinst.sh" + +test -f "$NEW/config.json" +test -f "$NEW/runs.json" +test -f "$NEW/secrets/secret.json" +test ! -e "$OLD" +test ! -e "$ROOT/boot/config/plugins/$OLD_NAME.plg" +grep -q '/usr/local/libexec/urbm/restic' "$NEW/config.json" +grep -q '/mnt/user/urbm-restores' "$NEW/config.json" +grep -q '/mnt/user/system/urbm-logs' "$NEW/config.json" diff --git a/webgui/Backupper.page b/webgui/URBM.page similarity index 77% rename from webgui/Backupper.page rename to webgui/URBM.page index c021dd2..404c32e 100644 --- a/webgui/Backupper.page +++ b/webgui/URBM.page @@ -1,20 +1,20 @@ Menu="Tasks:55" Name="Backup" -Icon="backupper.png" +Icon="urbm.png" Type="xmenu" Tabs="true" Code="f0c7" Tag="URBM Unraid Restic Backup Manager backup snapshots restore" --- - -
+ +
- -

URBM 2026.06.14.r001

Restic Backup Manager für Unraid

+ +

URBM 2026.06.14.r002

Restic Backup Manager für Unraid

Verbindung wird hergestellt...
@@ -31,5 +31,5 @@ $pluginRoot = '/plugins/backupper';
- - + + diff --git a/webgui/api.php b/webgui/api.php index 597d095..364d024 100644 --- a/webgui/api.php +++ b/webgui/api.php @@ -3,7 +3,7 @@ declare(strict_types=1); header('Content-Type: application/json'); -$socket = '/run/backupper/backupper.sock'; +$socket = '/run/urbm/urbm.sock'; $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; $path = $_GET['path'] ?? '/v1/health'; @@ -15,7 +15,7 @@ if (!preg_match('#^/v1/[A-Za-z0-9_./?=&%:-]*$#', $path) || str_contains($path, ' if (!file_exists($socket)) { http_response_code(503); - echo json_encode(['error' => 'URBM daemon is not running']); + echo json_encode(['error' => 'Der URBM-Daemon läuft nicht']); exit; } @@ -42,7 +42,7 @@ curl_close($curl); if ($response === false) { http_response_code(502); - echo json_encode(['error' => 'Daemon connection failed: ' . $error]); + echo json_encode(['error' => 'Verbindung zum URBM-Daemon fehlgeschlagen: ' . $error]); exit; } diff --git a/webgui/assets/backupper.css b/webgui/assets/urbm.css similarity index 78% rename from webgui/assets/backupper.css rename to webgui/assets/urbm.css index 130de48..d677cb0 100644 --- a/webgui/assets/backupper.css +++ b/webgui/assets/urbm.css @@ -1,4 +1,4 @@ -#backupper-app { +#urbm-app { --bu-page: transparent; --bu-panel: var(--mild-background-color, #ffffff); --bu-panel-alt: var(--background-color, #f3f5f7); @@ -23,15 +23,15 @@ .bu-header { align-items: center; display: flex; justify-content: space-between; margin: 6px 0 22px; } .bu-brand { align-items: center; display: flex; gap: 14px; min-width: 0; } .bu-logo { display: block; flex: 0 0 auto; height: 58px; object-fit: contain; width: 58px; } -#backupper-app .bu-header h1 { color: var(--bu-text) !important; font-size: 30px; font-weight: 700; line-height: 1.2; margin: 0; } +#urbm-app .bu-header h1 { color: var(--bu-text) !important; font-size: 30px; font-weight: 700; line-height: 1.2; margin: 0; } .bu-version { border: 1px solid var(--bu-border); border-radius: 999px; display: inline-block; font-size: 12px; font-weight: 600; padding: 2px 7px; vertical-align: middle; } -#backupper-app .bu-header p { color: var(--bu-muted) !important; font-size: 16px; margin: 5px 0 0; opacity: .78; } +#urbm-app .bu-header p { color: var(--bu-muted) !important; font-size: 16px; margin: 5px 0 0; opacity: .78; } .bu-health { background: var(--bu-panel); border: 1px solid var(--bu-border); border-radius: 999px; color: var(--bu-text); font-weight: 600; padding: 9px 15px; } .bu-health.ok { color: var(--bu-good); } .bu-health.bad { color: var(--bu-bad); } .bu-tabs { border-bottom: 2px solid var(--bu-border-strong); display: flex; gap: 3px; margin-bottom: 20px; overflow-x: auto; } -#backupper-app .bu-tabs button { +#urbm-app .bu-tabs button { appearance: none; background: transparent !important; border: 0 !important; @@ -52,13 +52,13 @@ text-transform: none; white-space: nowrap; } -#backupper-app .bu-tabs button:hover { color: var(--bu-text) !important; opacity: 1; } -#backupper-app .bu-tabs button.active { border-bottom-color: var(--bu-accent) !important; color: var(--bu-text) !important; opacity: 1; } +#urbm-app .bu-tabs button:hover { color: var(--bu-text) !important; opacity: 1; } +#urbm-app .bu-tabs button.active { border-bottom-color: var(--bu-accent) !important; color: var(--bu-text) !important; opacity: 1; } .bu-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); } .bu-chart-grid-layout { display: grid; gap: 16px; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-top: 16px; } .bu-card { background: var(--bu-panel); border: 1px solid var(--bu-border); border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,.12); color: var(--bu-text); padding: 18px; } -#backupper-app .bu-card h2, #backupper-app .bu-card h3 { color: var(--bu-text) !important; font-weight: 700; margin-top: 0; } +#urbm-app .bu-card h2, #urbm-app .bu-card h3 { color: var(--bu-text) !important; font-weight: 700; margin-top: 0; } .bu-stat { color: var(--bu-text); font-size: 32px; font-weight: 700; } .bu-chart { display: block; height: 240px; margin-top: 12px; overflow: visible; width: 100%; } .bu-chart-grid line { stroke: var(--bu-border); stroke-width: 1; } @@ -67,7 +67,7 @@ .bu-chart-line { fill: none; stroke: var(--bu-accent); stroke-linecap: round; stroke-linejoin: round; stroke-width: 3; } .bu-chart-dots circle { fill: var(--bu-panel); stroke: var(--bu-accent); stroke-width: 3; } .bu-chart-empty { align-items: center; color: var(--bu-muted); display: flex; height: 240px; justify-content: center; text-align: center; } -#backupper-app .bu-muted { color: var(--bu-muted) !important; opacity: .72; } +#urbm-app .bu-muted { color: var(--bu-muted) !important; opacity: .72; } .bu-toolbar { align-items: center; display: flex; flex-wrap: wrap; gap: 8px; justify-content: space-between; margin-bottom: 14px; } .bu-actions { display: flex; flex-wrap: wrap; gap: 7px; } .bu-table-actions { align-items: flex-start; min-width: 310px; } @@ -91,10 +91,10 @@ .bu-weekdays { align-items: center; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; } .bu-weekdays[hidden] { display: none; } .bu-weekdays > span { font-weight: 700; margin-right: 4px; } -#backupper-app .bu-weekdays label { display: block; } -#backupper-app .bu-weekdays label span { background: var(--bu-panel-alt); border: 1px solid var(--bu-border-strong); border-radius: 5px; cursor: pointer; display: block; min-width: 46px; padding: 9px 11px; text-align: center; } -#backupper-app .bu-weekdays input { opacity: 0; pointer-events: none; position: absolute; } -#backupper-app .bu-weekdays input:checked + span { background: var(--bu-accent) !important; border-color: var(--bu-accent) !important; color: #fff !important; } +#urbm-app .bu-weekdays label { display: block; } +#urbm-app .bu-weekdays label span { background: var(--bu-panel-alt); border: 1px solid var(--bu-border-strong); border-radius: 5px; cursor: pointer; display: block; min-width: 46px; padding: 9px 11px; text-align: center; } +#urbm-app .bu-weekdays input { opacity: 0; pointer-events: none; position: absolute; } +#urbm-app .bu-weekdays input:checked + span { background: var(--bu-accent) !important; border-color: var(--bu-accent) !important; color: #fff !important; } .bu-custom-cron { margin-top: 14px; } .bu-event-options { display: flex; flex-wrap: wrap; gap: 10px; } .bu-progress-wrap { min-width: 280px; } @@ -112,12 +112,12 @@ .bu-form-grid { display: grid; gap: 15px; grid-template-columns: repeat(2, minmax(220px, 1fr)); } .bu-managed-mount, .bu-external-mount { margin-top: 14px; } .bu-managed-mount[hidden], .bu-external-mount[hidden] { display: none; } -#backupper-app .bu-inline-check { align-items: center; display: flex; gap: 9px; grid-template-columns: auto 1fr; } -#backupper-app .bu-inline-check input { margin: 0; } -#backupper-app .bu-event-options label { align-items: center; display: flex; gap: 7px; grid-template-columns: auto auto; } -#backupper-app .bu-event-options input[type="checkbox"] { margin: 0; min-height: 20px; width: 20px; } +#urbm-app .bu-inline-check { align-items: center; display: flex; gap: 9px; grid-template-columns: auto 1fr; } +#urbm-app .bu-inline-check input { margin: 0; } +#urbm-app .bu-event-options label { align-items: center; display: flex; gap: 7px; grid-template-columns: auto auto; } +#urbm-app .bu-event-options input[type="checkbox"] { margin: 0; min-height: 20px; width: 20px; } -#backupper-app .bu-button { +#urbm-app .bu-button { appearance: none; background: var(--bu-panel-alt) !important; border: 1px solid var(--bu-border-strong) !important; @@ -132,11 +132,11 @@ padding: 8px 13px !important; text-shadow: none !important; } -#backupper-app .bu-button:hover { border-color: var(--bu-accent) !important; } -#backupper-app .bu-button.primary { background: var(--bu-accent) !important; border-color: var(--bu-accent) !important; color: #ffffff !important; } -#backupper-app .bu-button.primary:hover { background: var(--bu-accent-hover) !important; } -#backupper-app .bu-button.danger { color: var(--bu-bad) !important; } -#backupper-app .bu-button:disabled { cursor: wait; opacity: .55; } +#urbm-app .bu-button:hover { border-color: var(--bu-accent) !important; } +#urbm-app .bu-button.primary { background: var(--bu-accent) !important; border-color: var(--bu-accent) !important; color: #ffffff !important; } +#urbm-app .bu-button.primary:hover { background: var(--bu-accent-hover) !important; } +#urbm-app .bu-button.danger { color: var(--bu-bad) !important; } +#urbm-app .bu-button:disabled { cursor: wait; opacity: .55; } .bu-table { border-collapse: collapse; color: var(--bu-text); width: 100%; } .bu-table th, .bu-table td { border-bottom: 1px solid var(--bu-border); color: var(--bu-text); padding: 12px 8px; text-align: left; vertical-align: top; } @@ -147,12 +147,12 @@ .bu-status.running, .bu-status.queued, .bu-status.paused, .bu-status.warning { background: rgba(232,93,36,.10); color: var(--bu-accent); } .bu-form { display: grid; gap: 15px; grid-template-columns: repeat(2, minmax(220px, 1fr)); } -#backupper-app .bu-form label { color: var(--bu-text) !important; display: grid; font-size: 14px; font-weight: 600; gap: 7px; } +#urbm-app .bu-form label { color: var(--bu-text) !important; display: grid; font-size: 14px; font-weight: 600; gap: 7px; } .bu-form .wide { grid-column: 1 / -1; } -#backupper-app .bu-form input, -#backupper-app .bu-form select, -#backupper-app .bu-form textarea, -#backupper-app select { +#urbm-app .bu-form input, +#urbm-app .bu-form select, +#urbm-app .bu-form textarea, +#urbm-app select { background: var(--bu-input) !important; border: 1px solid var(--bu-border-strong) !important; border-radius: 5px !important; @@ -162,26 +162,26 @@ min-height: 40px; padding: 9px 10px !important; } -#backupper-app .bu-form input:focus, -#backupper-app .bu-form select:focus, -#backupper-app .bu-form textarea:focus, -#backupper-app button:focus-visible { +#urbm-app .bu-form input:focus, +#urbm-app .bu-form select:focus, +#urbm-app .bu-form textarea:focus, +#urbm-app button:focus-visible { border-color: var(--bu-accent) !important; box-shadow: 0 0 0 3px var(--bu-focus) !important; outline: none; } -#backupper-app .bu-form input[type="checkbox"] { accent-color: var(--bu-accent); min-height: 22px; width: 22px; } -#backupper-app .bu-form textarea { min-height: 100px; resize: vertical; } +#urbm-app .bu-form input[type="checkbox"] { accent-color: var(--bu-accent); min-height: 22px; width: 22px; } +#urbm-app .bu-form textarea { min-height: 100px; resize: vertical; } .bu-empty { color: var(--bu-text); font-size: 15px; opacity: .72; padding: 34px; text-align: center; } #bu-toast { background: var(--bu-panel); border: 1px solid var(--bu-border-strong); border-radius: 6px; bottom: 24px; color: var(--bu-text); display: none; font-weight: 600; max-width: 460px; padding: 12px 16px; position: fixed; right: 24px; z-index: 20; } #bu-toast.show { display: block; } #bu-toast.error { border-color: var(--bu-bad); color: var(--bu-bad); } -#backupper-app [data-tooltip] { cursor: help; } -#backupper-app button[data-tooltip], -#backupper-app input[data-tooltip], -#backupper-app select[data-tooltip], -#backupper-app textarea[data-tooltip] { cursor: pointer; } +#urbm-app [data-tooltip] { cursor: help; } +#urbm-app button[data-tooltip], +#urbm-app input[data-tooltip], +#urbm-app select[data-tooltip], +#urbm-app textarea[data-tooltip] { cursor: pointer; } #bu-tooltip { background: #15191d; border: 1px solid #59636d; @@ -217,7 +217,7 @@ } @media (max-width: 700px) { - #backupper-app { padding-left: 8px; padding-right: 8px; } + #urbm-app { padding-left: 8px; padding-right: 8px; } .bu-form { grid-template-columns: 1fr; } .bu-workload-options { grid-template-columns: 1fr; } .bu-retention-grid { grid-template-columns: 1fr; } diff --git a/webgui/assets/backupper.js b/webgui/assets/urbm.js similarity index 99% rename from webgui/assets/backupper.js rename to webgui/assets/urbm.js index 7e7076f..b36f331 100644 --- a/webgui/assets/backupper.js +++ b/webgui/assets/urbm.js @@ -1,6 +1,6 @@ (() => { 'use strict'; - const root = document.getElementById('backupper-app'); + const root = document.getElementById('urbm-app'); if (!root) return; const content = document.getElementById('bu-content'); const health = document.getElementById('bu-health'); @@ -36,12 +36,12 @@ knownHostsPath: 'Datei mit dem geprüften SSH-Hostschlüssel. Beispiel: /root/.ssh/known_hosts. StrictHostKeyChecking ist immer aktiv.', snapshotId: 'Eindeutige ID des Sicherungsstands. Beispiel: 7f3a91cd. Sie kann im Bereich Snapshots über Durchsuchen ausgewählt werden.', includes: 'Nur diese Pfade werden wiederhergestellt, einer pro Zeile. Beispiel: /mnt/user/Documents/Rechnung.pdf oder /mnt/user/Documents.', - target: 'Zielverzeichnis der Wiederherstellung. Sicheres Beispiel: /mnt/user/backupper-restores/restore-123. Standardmäßig wird nicht direkt über Originaldaten geschrieben.', + target: 'Zielverzeichnis der Wiederherstellung. Sicheres Beispiel: /mnt/user/urbm-restores/restore-123. Standardmäßig wird nicht direkt über Originaldaten geschrieben.', inPlace: 'Erlaubt Wiederherstellung direkt an einen produktiven Zielpfad. Nur aktivieren, wenn vorhandene Dateien bewusst ersetzt werden sollen.', confirmed: 'Zusätzliche Bestätigung für einen In-place-Restore. Ohne diese Bestätigung wird ein direkter Restore blockiert.', - resticPath: 'Pfad zur vom Plugin bereitgestellten Restic-Datei. Standard: /usr/local/libexec/backupper/restic. Normalerweise nicht ändern.', - restoreRoot: 'Basisverzeichnis für sichere Staging-Restores. Beispiel: /mnt/user/backupper-restores.', - persistentLogDir: 'Optionales Verzeichnis für dauerhafte Detailprotokolle. Beispiel: /mnt/user/system/backupper-logs. Leer lassen, um Flash-Schreibzugriffe zu vermeiden.', + resticPath: 'Pfad zur vom Plugin bereitgestellten Restic-Datei. Standard: /usr/local/libexec/urbm/restic. Normalerweise nicht ändern.', + restoreRoot: 'Basisverzeichnis für sichere Staging-Restores. Beispiel: /mnt/user/urbm-restores.', + persistentLogDir: 'Optionales Verzeichnis für dauerhafte Detailprotokolle. Beispiel: /mnt/user/system/urbm-logs. Leer lassen, um Flash-Schreibzugriffe zu vermeiden.', showLiveLog: 'Zeigt bereinigte Restic-Laufmeldungen unter den Aufgaben im Aktivitäten-Bereich. Standardmäßig deaktiviert; Fortschritt und Ergebnis bleiben trotzdem sichtbar.', catchUp: 'Wie viele Stunden nach einem verpassten Termin ein Job beim Boot nachgeholt werden darf. Beispiel: 24 holt einen innerhalb des letzten Tages verpassten Lauf nach.', checkCron: 'Zeitplan für vollständige Repository-Prüfungen. Beispiel: 0 3 1 * * prüft am ersten Tag jedes Monats um 03:00 Uhr.', @@ -102,7 +102,7 @@ const api = async (path, options = {}) => { const response = await fetch(`${root.dataset.api}?path=${encodeURIComponent(path)}`, { ...options, - headers: {'Content-Type':'application/json', 'X-CSRF-Token':window.BACKUPPER_CSRF || window.csrf_token || '', ...(options.headers || {})} + headers: {'Content-Type':'application/json', 'X-CSRF-Token':window.URBM_CSRF || window.csrf_token || '', ...(options.headers || {})} }); const text = await response.text(); let body = null; diff --git a/webgui/images/backupper.png b/webgui/images/urbm.png similarity index 100% rename from webgui/images/backupper.png rename to webgui/images/urbm.png