Skip to content

Releases: Joulenap/joulenap

v1.2.1

Choose a tag to compare

@catubba catubba released this 24 Aug 13:07
30c53e2

Patch release for #51.

Fixed

  • A sync route that pulls now tells PBS who owns the backups it fetches, namely the API token Joulenap uses on the receiving server. Without that field PBS falls back to root@pam, and the run fails on every group with "owner check failed" as soon as the target datastore already holds backups owned by the token, which is the normal state of any datastore Joulenap itself backs up to (#51). Push routes were never affected: pushed backups belong to the account named in the remote configuration, whatever the job asks for.

Upgrading

A pull route that ran before this fix wrote its groups on the target as root@pam, so the first run afterwards reports the same owner mismatch the other way round. Reassign those groups once on the receiving server, with Change Owner in the datastore's Content tab or with proxmox-backup-client change-owner.

Docker

catubba/joulenap:1.2.1 (also :latest), digest sha256:e86063e8ae6648df1e7a8f621fbe7775976509153c153c0d19e98a5baf8248b4.

Full changelog: https://github.com/Joulenap/joulenap/blob/main/CHANGELOG.md

v1.2.0

Choose a tag to compare

@catubba catubba released this 23 Aug 12:06
1fccefd

Set-and-forget backup routes, and guest names back in the Notes column.

Added

  • Backup routes gained an Exclude guest mode next to All and Selection: the route covers everything on its sources except the guests you tick, so a VM or container created later is backed up on the next run without touching the route. The exclusion is handed to vzdump itself (--all with --exclude), so Proxmox keeps deciding which guests a run covers and a guest marked exclude from backup on the host is still honoured (#46).
  • Each of the three guest modes now explains itself under the switch, including the one that was missing before: Selection says outright that a guest created later has to be added by hand.
  • Backups triggered by Joulenap now carry the guest name in their Notes, the way a backup job created in the Proxmox VE web interface does. Both the PVE and PBS backup lists show the name next to the ID again, so picking the right snapshot to restore no longer means matching VMIDs by hand (#48).

Changed

  • A route that excludes every guest is refused at save time, the rule that already covered a Selection with nothing ticked. Either one wakes the backup server on schedule and aborts the run without ever writing a backup.
  • A 0.9 config that used the old exclude guest mode migrates straight through instead of widening to all with a warning.

Upgrading

Nothing to do. Existing routes keep the mode they have, and the new one is opt-in per source.

Docker

catubba/joulenap:1.2.0 (also :latest), digest sha256:e906e9e4e6b6bb63602c46f1c8d132855d29cc53fbcb7173baf1f3b5dc844e77.

Full changelog: https://github.com/Joulenap/joulenap/blob/main/CHANGELOG.md

v1.1.3

Choose a tag to compare

@catubba catubba released this 21 Aug 21:19
fa5be53

Patch release for #44, and the second half of the fix started in 1.1.2.

Fixed

  • The reachability probe now makes a real request instead of shaking hands and hanging up. proxmox-backup-proxy prepares each connection, peer address and all, in the moment right after the handshake, and a client that disappears exactly then left Failed to get api service: Transport endpoint is not connected in the PBS syslog on every poll. The probe now asks for GET / and reads the answer to the end, which is one round trip and about 30 ms on a LAN (#44).

Docker

catubba/joulenap:1.1.3 (also :latest), digest sha256:271a9ca33a99996fa58b45c9a7acf0f86fabd1d3eb1360dea6bc4e5a802de643.

Full changelog: https://github.com/Joulenap/joulenap/blob/main/CHANGELOG.md

v1.1.2

Choose a tag to compare

@catubba catubba released this 20 Aug 22:57

Patch release for #44.

Fixed

  • The reachability probe that tells an awake PBS from a sleeping one now completes the TLS handshake instead of opening a connection and closing it without speaking. The old probe made proxmox-backup-proxy write failed to check for TLS handshake and Failed to get api service to the PBS syslog on every poll, roughly every 8 seconds while a dashboard was open (#44).

Docker

catubba/joulenap:1.1.2 (also :latest), digest sha256:dcf997a32a8144c9f9e2035d0030d66a36f028506692238ae262663d2f8d8ea0.

Full changelog: https://github.com/Joulenap/joulenap/blob/main/CHANGELOG.md

v1.1.1

Choose a tag to compare

@catubba catubba released this 16 Aug 23:15
f39459b

Patch release for #38, follow-up to 1.1.0.

Fixed

  • A run that could not create its own history row (SQLite database is locked past the busy timeout, a full disk) used to vanish: no row, no notification, one line in the container log, so a scheduled sync looked as if it had never fired. It is now reported on the configured notification channels as a failed run (without a run number) and the single-run lock is released as usual (#38).
  • The SQLite database now uses synchronous=NORMAL with WAL, so a commit no longer fsyncs on every task-log line, and the busy timeout is 30 s instead of 5 s. A disk that stalls for a few seconds under a running backup (a VM on spinning disks, for instance) no longer turns a task-log write into database is locked and a failed run. In WAL this remains safe across an application crash; a power loss can at worst lose the last few seconds of run history, never corrupt the file (#38).

Docker

catubba/joulenap:1.1.1 (also :latest), digest sha256:c6485c912ee51341f3d8958c7cb5d06656ad0b78d5c8ce16b34ef20867947d77.

Full changelog: https://github.com/Joulenap/joulenap/blob/main/CHANGELOG.md

v1.1.0

Choose a tag to compare

@catubba catubba released this 16 Aug 16:43
401ff6a

Docker image: catubba/joulenap:1.1.0 (also :latest) — digest sha256:338f9df08dcb4af806721edad90243aa45efecd96381a32d82082a77a5c0d0c5.

Added

  • Sync routes can now keep an independent, tighter retention on the target: the route's retention (already shown in the form, but until now not applied to sync routes) is pruned on the target datastore after each sync, before GC. All-zero retention means no prune, and protected snapshots are never removed. Two new sync options in the route form: transfer_last (copy only the newest N snapshots per group, PBS transfer-last) and remove_vanished (delete on the target what disappeared from the source, PBS remove-vanished; opt-in, off by default). Together they let an off-site or S3-backed copy stay smaller than its source instead of re-growing to it on every run (#36).
  • The PBS token grant for sync routes is now RemoteAdmin + RemoteDatastoreAdmin (was RemoteSyncPushOperator): a push job with remove_vanished needs Remote.DatastorePrune, which the old role lacks. A box granted by 1.0 keeps working as before; re-run Grant sync permissions on it (Settings → Devices → edit the PBS that creates the job: the source for push, the target for pull) before turning remove_vanished on for a push route, or PBS refuses to create the job with "permission check failed".

Fixed

  • Long-running tasks are no longer failed at 6 hours. The wait on a PVE/PBS task had a hard 6-hour cap, so a first full sync to an S3/Backblaze datastore was reported as failed (unknown status) while the PBS worker went on and completed. The cap is now a no-progress timeout: a task that keeps writing to its log runs as long as it needs, one that goes silent for 6 hours fails with timeout 6h (#37).
  • A run could stay "Running" forever after its worker died: if a database write failed at the wrong moment (a locked or slow SQLite at the peak of the log tail), the session was left unusable, the step and the run could not be closed out, and only a restart's sweep ended them, while Stop run answered "not the one in progress". Writes now recover from a failed commit, a run whose session died is still closed out on a fresh one, and Stop run on such an orphaned row marks it interrupted instead of refusing (#38).
  • The task log of a backup no longer starts with PVE's "no content" placeholder, which was also swallowing the real first line of the vzdump output (#38).

Changed

  • If you had a sync route configured before this release, its retention block was saved with the form defaults (keep-daily 7 / weekly 4 / monthly 6) and did nothing. It now prunes the target with those values on the next run: review it, or set every keep-* to 0 to keep the old "never prune" behaviour.

v1.0.0 Multi-PVE / Multi-PBS release

Choose a tag to compare

@catubba catubba released this 07 Aug 14:26

Joulenap is no longer built around one Proxmox host backing up to one backup server. It now models
devices — any number of PVEs and any number of PBSs — and routes between them. Existing
configurations are converted automatically on the first start; see Changed below for the one
conversion that is lossy, and for the two breaking changes outside the interface.

After upgrading, expect one alarming-looking display that is not a problem. Backup history is
tracked per route, and the conversion gives your old schedule new route ids, so Last backup per
guest
reads "never" for every guest and the converted routes read "never run" — with all the old
runs still listed underneath. Nothing has been lost: the caches fill in again per guest as runs
happen, and the first run of each route restores its badge.

One limitation worth knowing before you configure. Joulenap reads the root namespace of a
backup datastore, so if your Proxmox storage entry writes into a PBS namespace the backups, the
retention and the garbage collection all work, but Last backup per guest reads "never" for those
guests.

Added

  • Routes. A route is one scheduled flow of backup data between devices: sources, a target, its
    own time and weekdays, its own retention, its own options. Four kinds, inferred from the devices
    you pick: backup (one or more Proxmox hosts into a backup server, including a fan-in from
    several at once), sync (one backup server into another, pull or push, for a real off-site
    second copy), external (Joulenap starts nothing and only watches the jobs PVE and PBS run on
    their own schedules), and verify. Guests are selected per source, because vmids collide
    between hosts.

  • Multiple Proxmox hosts and multiple backup servers. Each is a device with its own address,
    scoped token, TLS fingerprint and — for a backup server — its own wake-up and power-off settings.
    A backup server you keep powered on all the time is supported: turn managed_power off and
    Joulenap treats it as always available instead of trying to wake it.

  • A run queue and a per-server power lease. One run is ever in flight; the rest wait their turn
    instead of being dropped. Each backup server a run needs is leased: the first holder wakes it, the
    last release powers it off — and only if nothing still queued needs it, the run succeeded, and you
    did not ask to keep it on. So two routes an hour apart on the same box wake it once, and a sync
    route wakes both boxes and releases them independently. The power-off step in the run timeline
    says which of those happened.

  • A rebuilt interface. The homepage is now an operations view: a live backup map of your hosts
    and backup servers with the routes drawn between them, the route strip where routes are created,
    edited, paused and run by hand, what is coming up next, and a run history whose rows expand into a
    per-step timeline with the PVE/PBS task output streaming underneath. Settings became five tabs
    (Devices, Account, Notifications, Integrations, Advanced) with a device card and edit modal for
    every box, and a removal guard that names the routes still using one.

  • Two guided wizards, replacing the single linear setup. Add a Proxmox VE connects and then
    reads that host's storage configuration to discover the backup servers behind it, linking the ones
    you already registered and offering to configure a new one inline. Add a Proxmox Backup Server
    walks connection, wake-up (with a Test button that sends a real magic packet before you find out
    at 04:00 that Wake-on-LAN was never armed) and power-off. Both work from pasted API tokens, or
    provision everything themselves from a root login used once and never stored. Detect MAC now
    works in the container: it used to shell out to ping, which the image does not contain, so it
    only ever found a machine something else had recently talked to. The Wake-on-LAN interface is
    a list of the host's own NICs instead of a text box in which a typo silently fell back to
    auto-detection.

  • A backup server's API token is named after its datastorejoulenap-backup,
    joulenap-offsite — so one machine serving several datastores gets one token per device instead
    of the setups fighting over a single name. Deleting an API token also drops the permissions
    granted to it, so a shared name would have meant configuring the second datastore left the first
    one both locked out and unrepairable by re-entering its secret. A Proxmox host is one device and
    keeps the plain joulenap. Tokens already in use are untouched; the name only applies to ones
    Joulenap creates from now on.

  • Ad-hoc maintenance per backup server. Run a garbage collection or a verification on one box
    from the homepage, without a route. It queues and reports like any other run; only the route
    column is empty.

  • A route can be stopped and a config.yaml can be exported. Stopping a run also stops the
    PVE/PBS task behind it and asks whether to power the server down.

  • The header pill reports health, not just activity. While nothing is running it answers the
    morning-after question directly: green "All OK" with the next fire when the last run succeeded,
    red with the route's name and the time when it failed. A run you stopped yourself reads as plain
    idle — a deliberate stop is not a failure.

  • Every action sits on the thing it acts on. Each route card has its own Run button, and each
    backup server card in the map has Run GC and Run verify; all three open a confirm dialog already
    aimed at that route or box. The Manual run panel and its "which one?" dropdowns are gone, and
    Upcoming runs uses the freed column to show about twice as much of the schedule.

  • A guest that has never been backed up is called out — highlighted in the guest list, with a
    count in the panel header that a search filter cannot hide.

Changed

  • GET /api/dashboard and /metrics changed shape, and this breaks existing widgets and
    alerts.
    With several routes and several backup servers there is no single "next run" or "the
    datastore" left to report. The dashboard payload is now {state, routes[], pbss[]}, so a widget
    picks a list entry (routes.0.next_run) instead of a flat field. Prometheus series are labelled:
    joulenap_next_run_timestamp_seconds became
    joulenap_route_next_run_timestamp_seconds{route="..."}, the joulenap_last_run_* family became
    joulenap_route_last_run_*{route="..."}, every PBS and datastore series carries pbs=, and
    per-guest freshness is now labelled {vmid, pve, pbs} because a vmid alone stopped being unique.
    The field-by-field mapping is at the top of docs/INTEGRATIONS.md, and Settings → Integrations
    always shows a snippet generated for the version you are running.

  • Your config.yaml is migrated automatically, with a parachute. The pve:, pbs: and
    backup: sections become pves[], pbss[] and routes[] on the first start after the upgrade:
    the backup job becomes a route named Backup, a scheduled verification becomes one named Verify,
    and schedules, guest selections and retention come across with them. The original file is copied
    to config.yaml.pre-overhaul.bak first. If the converted config fails validation the file on disk
    is left untouched, but the app then starts with no devices and no routes — nothing is scheduled
    until it is fixed — and says so in a banner rather than looking like a fresh install.

  • The exclude guest mode is gone, and a migrated route widens to "all guests". Inverting an
    exclusion list needs a live guest list that is not available while the config is being read, so
    such a route is converted to "all" and a warning is logged. It will back up more than before,
    never less — but it is worth checking after the upgrade.

  • Garbage collection and verification are per-route options, set in the route editor's Advanced
    section, rather than global maintenance settings. maintenance: now holds only how long run
    history is kept.

  • Guest selection and retention moved out of Settings and into the route that uses them. So did
    backup mode, the bandwidth cap and the minimum-free-space check. Wake timeout, Wake-on-LAN retries
    and the external-watch timeouts belong to a backup server and live on its device card.

  • GET /api/guests now requires a ?pve= parameter and reports, per guest, which backup servers
    hold a snapshot of it. Collapsing newest-per-vmid across every host would have shown the wrong
    host's backup date once a second one existed.

  • Notifications name the route and no longer describe every missed run as a missed backup. A run
    that fails reports its error translated, in the interface as well as in the notification. A garbage
    collection or verification started by hand has no route, so it names the backup server instead.

  • Contrast, focus and keyboard behavior were retuned across the interface. Muted text meets
    WCAG AA, input borders meet 3:1, keyboard focus is visible everywhere, dialogs start focused on
    their first field, error banners scroll into view instead of appearing off-screen, Enter saves
    the route editor, the language and timezone pickers are native selects, and a failed route
    toggle reports why instead of silently snapping back. On phones the run history becomes cards,
    the map stacks, and touch targets grow to 44px.

Removed

  • The single pve: / pbs: / backup: config sections, along with pve.node (cluster nodes
    are discovered at runtime, which is also how a cluster is detected) and pve.storage_id (a host
    now maps each backup server to the storage it uses for it).
  • External schedules as a global mode. It is a route kind now, so one backup server can be
    watched while another is driven by Joulenap — which the global switch made impossible.
  • The endpoints the single-job model needed: `POST /api/backup...
Read more

v0.9.0 — External schedules mode

Choose a tag to compare

@catubba catubba released this 29 Jul 08:00
d2bf475

Added

  • External schedules mode. For setups whose backup, prune, GC and sync jobs are already scheduled natively on PVE/PBS: Joulenap can now act purely as the power manager — at the scheduled time it wakes the PBS, watches the tasks the servers start on their own, and powers it off once they have been quiet for a configurable window. Selected with a new switch at the top of the Schedule card ("Scheduled by Joulenap" / "External schedules"); in external mode Joulenap starts no backup or GC of its own, and the run history records the watch as its own run kind with the number of tasks observed. A wake where no job ever appears still powers the PBS back off and says so in the notification, so a misfiring PVE/PBS schedule is noticed instead of silently missed. (#27)
  • Live demo build. npm run build:demo emits a self-contained copy of the UI that answers its own API calls from fixtures, so it can be hosted as static files (joulenap.com/demo). It opens on the dashboard with no login, carries an orange banner making clear the data is fake, and replays a scripted backup cycle — wake, vzdump, prune, GC, power off — when you press Run backup now. The regular npm run build that the container image uses never includes any of it.

Docker

docker pull catubba/joulenap:0.9.0

Digest: sha256:416d7d00aa143188622feabc611cff352e3d6ecaee7bacd8471fc07b9c4fc380 (:0.9.0 and :latest)

Full changelog: v0.8.0...v0.9.0

v0.8.0 — Richer notifications

Choose a tag to compare

@catubba catubba released this 25 Jul 20:43
b4a443b

Added

  • Notifications say a lot more. Every run notification now opens with what started the run
    (scheduled or manual), breaks the duration down by phase
    (12m 34s (backup 7m 10s · GC 1m 6s)), reports guests as a fraction with the names of the ones
    that failed (Guests: 12/14 (failed: web01, db02)), and closes with the next scheduled run and
    the run number. The alert for a run a restart interrupted also states how long the PBS has been
    awake. All of it is translated in both languages.
  • Run history shows the run number. A new first column, so the Run #128 a notification
    quotes can actually be looked up in the interface.
  • A failed backup names the guest that broke. Proxmox runs one vzdump task for all selected
    guests, so a single guest failing used to fail the run with no indication of which one; the
    outcome is now read off the task log as it streams, so the notification can name it.

Fixed

  • Notification bodies keep their line breaks. Channels that deliver in HTML (email, Telegram)
    collapsed the whole body onto a single line because Apprise was never told the text was plain
    text.
  • Notification timestamps all use the configured timezone. In the missed-backup alert the
    "Last backup run" line was rendered in UTC while the two lines around it used app.timezone,
    so the same message could disagree with itself by hours.

Docker

docker pull catubba/joulenap:0.8.0

Image digest: sha256:3ae72d6220fd07bcb3680859a9324c53ac52508a28efb59a746513664bf1c003
(also tagged latest).

Full changelog: v0.7.0...v0.8.0

Joulenap 0.7.0

Choose a tag to compare

@catubba catubba released this 23 Jul 21:39
7832e11

Added

  • Light theme. The interface now ships the light theme that app.theme always promised: a header toggle (moon/sun, between the Settings and Logout buttons) switches the whole interface — dashboard, settings, dialogs and the config.yaml editor included — with a short cross-fade, and remembers the choice in config.yaml so it survives restarts and follows you to other browsers. The login screen picks up the last theme used on that device. Dark remains the default, and existing installations that never touch the toggle look exactly as before. Users who have asked their system to reduce motion get an instant switch instead of the fade.

Fixed

  • The app.theme config value is honoured. It was accepted and stored since 0.1.0 but never read; setting it to light now actually applies the light theme at startup.
  • Header buttons render at the same height. The Logout button was a few pixels shorter than its neighbours.

Docker

catubba/joulenap:0.7.0 / catubba/joulenap:latest — digest sha256:651375718b7afb868e171770b80becbf16a18bf11e4b0b5e2e1945210bfbedf6