TRANSACTIONAL-UPDAT(8)

πŸ“¦ version 5.0.9, in opensuse-leap 16.0

🌸 NAME 🌸

okay so this is the transactional-update(8) manual page, and it's literally about transactional-update, transactional-update.service, and transactional-update.timer β€” the whole slay crew that applies updates to the system in an atomic way via transactional updates. βœ¨πŸ’…


✨ SYNOPSIS ✨

transactional-update [options...] [general-command...]
                     [package-command [command-argument...]]

transactional-update [options...] standalone-command

transactional-update.service

transactional-update.timer

πŸ’– DESCRIPTION πŸ’–

bestie, here's the tea: transactional-update updates your system in a transactional way. that means updates are atomic β€” either the patches are fully applied or nothing is changed, periodt. the update does not influence the running system, and it can be rolled back. to activate the changes, the system needs to be rebooted. πŸ‘‘

to pull this off, transactional-update is using Btrfs' snapshot mechanism, combined with the default distribution tools. whenever an update of the root file system is going to be performed, snapper(8) will create a new snapshot of the root file system first. this new snapshot is then used to perform the update, e.g. by calling zypper(8) with the -R option pointing to the new snapshot. if no errors occurred, the snapshot will be set as the new default snapshot and set as read-only. in case of errors, the snapshot will be deleted again. 😭πŸ”₯

by default the snapshot is always branched off from the current root file system, i.e. calling transactional-update multiple times without rebooting will create separate, independent snapshots β€” not containing the changes of the previous run. if multiple consecutive actions are to be executed, the --continue option can be used. this will still create a separate snapshot for each call, so it is possible to roll back to previous intermediate steps in case of errors. πŸŒ€πŸ«Ά

on read-only systems, each snapshot will contain a nested /etc subvolume. as configuration files may be modified after a snapshot was created and before a reboot is performed (e.g. via configuration management software), on first boot into the new snapshot the service transactional-update-sync-etc-state.service will copy these files into the new snapshot if they weren't also changed there. πŸ’œ

⚠️ Warning, no cap: if a file in /etc has been changed during the update and is also changed in the running system after the snapshot has been taken, then only the version of the new snapshot will be visible after a reboot. πŸ’€

older transactional-update versions were using multiple /etc overlays instead of BTRFS subvolumes; a migration mechanism is in place, the directories will still be removed if no snapshot is using them any more. 🌈

on read-write systems, please be aware that all changes done to the running root filesystem after snapshot creation are lost after the next reboot. for this reason the system should be rebooted as fast as possible after a successful update. πŸ˜€πŸ‘‘

for easier maintenance of big clusters, transactional-update is run by systemd.timer(5) in regular intervals. the specific time can be configured in /etc/systemd/system/transactional-update.timer.d/local.conf. see systemd.unit(5) for more information. ⏰✨

✨ COMMANDS ✨

okay so if you don't pass any of the commands below, transactional-update just falls back to whatever UPDATE_METHOD is set to in transactional-update.conf(5). very "we'll figure it out" of it πŸ’…

🌸 General Commands 🌸

Hii so these ones are mix-and-match β€” you can stack them together in any combination, and on top of that you can add exactly one Package Command. Genuinely the order of the General Commands does not matter at all, it's giving chaos-friendly πŸ’–

  • apply β€” mounts /usr, /etc and /boot of the (new) default snapshot into the currently running system. Lowkey the whole point is that you can use freshly installed packages directly without rebooting. When you use apply on a system where existing files are gonna get replaced (like during a system update), it behaves similarly to a regular zypper update where files of currently running applications also get replaced β€” but with the extra glow-up that the update itself already finished successfully as a whole, so you dodge those inconsistent states when an update fails 😭

Note that β€” in contrast to regular zypper updates β€” services will not be restarted automatically. Also, mounting those three directories is not one atomic operation, so there's a short timespan where the directories visible to the system are not in sync. tiny window of chaos, just so you know 🫢

  • cleanup β€” identical to calling both cleanup-snapshots and cleanup-overlays. two-for-one, we love a bundle ✨
  • cleanup-snapshots β€” if the current root filesystem is identical to the active root filesystem (that means: after a reboot, before transactional-update creates a new snapshot with updates), then all old snapshots without a cleanup algorithm get a cleanup algorithm set. The whole point is making sure old snapshots actually get deleted by snapper. See the section about cleanup algorithms in snapper(8) for the lore.
  • cleanup-overlays β€” removes all unreferenced (and therefore unused) /etc overlay directories inside /var/lib/overlay. bye bestie πŸ‘‹
  • grub.cfg β€” grub2-mkconfig(8) gets called to create a new /boot/grub2/grub.cfg configuration file for the bootloader.
  • bootloader β€” same as grub.cfg, but it will also rewrite the bootloader itself. overachiever πŸ’…
  • initrd β€” a new initrd is created in a snapshot.
  • kdump β€” a new initrd for kdump is created in a snapshot.
  • reboot β€” triggers a reboot after updating the system, bestie. several different reboot methods are supported, configurable via the REBOOT_METHOD configuration option in transactional-update.conf(5). By default rebootmgrd(8) is used to reboot the system according to the configured policies if the service is running, otherwise systemctl reboot gets called. iykyk πŸ”₯
  • run cmd β€” executes the command cmd inside a new snapshot. By default this snapshot will remain, but if --drop-if-no-change is set, the new snapshot gets dropped if there's no change in the file system. no-change no-snapshot, we respect the boundaries ✨

This command consumes all the remaining parameters, so it has to go in the last position. main character takes the whole stage πŸ’€

To use features like command lists (pipes, separators, all that), wrap the script into a shell command like so:

                      transactional-update run bash -c '
                        ls && date
                        if [ true ]; then
                          echo -n "Hello "
                          echo '\''world'\''
                        fi
                      '
  • setup-fips β€” installs the FIPS pattern package and configures the kernel command line parameter to activate FIPS mode. πŸ›‘οΈ

This command can not be combined with any Package Command other than install.

  • setup-kdump [--crashkernel=low[,high]] β€” sets up kdump on the system. If no --crashkernel option is specified, it'll use the values determined by kdumptool calibrate; otherwise the values of low and high (numbers in Megabytes) get used for the corresponding crashkernel kernel parameters β€” or a static value if you only specify low.

This command can not be combined with any Package Command other than install.

  • setup-selinux β€” sets up a SELinux system: it installs the default SELinux "Targeted policy" and enables it. πŸ”

This command can not be combined with any Package Command other than install.

  • shell β€” opens a shell so you can execute commands like zypper manually. After all the actions are done, and before the snapshot with the changes gets unmounted and switched to read-only, a shell is started inside the new snapshot as a chroot environment for testing and debugging. little peek behind the curtain, we love to see it 🫢

🌸 Package Commands 🌸

Package Commands invoke zypper(8) to perform actions on the RPM packages. Only one Package Command at a time, please β€” but you can combine it with any number of General Commands. πŸ’–

By default, commands that are usually invoked from scripts run in non-interactive mode (meaning they assume the default answer when there are questions), while commands typically called by the user run in interactive mode. You can change or enforce this behaviour with the --interactive and the --non-interactive options respectively.

And to facilitate scripting: Package Commands exit early if no packages were updated. If you combined them with General Commands, those won't be executed any more in that case. early exit, no drama πŸ¦‹

πŸ’« Non-interactive Package Commands

  • dist-upgrade, dup β€” if new updates are available, a new snapshot is created and zypper dup --no-allow-vendor-change is used to update the snapshot. Afterwards the snapshot is activated and will be used as the new root filesystem during next boot. πŸ‘‘
  • update, up β€” if new updates are available, a new snapshot is created and zypper up is used to update the snapshot. Afterwards the snapshot is activated and will be used as the new root filesystem during next boot.
  • patch β€” if new updates are available, a new snapshot is created and zypper patch is used to update the snapshot. Afterwards the snapshot is activated and will be used as the new root filesystem during next boot.
  • register arguments β€” registers a (commercial) system. It's a simple wrapper for SUSEConnect, since some commands may require access to the root file system (like when adding a new key to the RPM database, for example). Any arguments just get forwarded straight to SUSEConnect.

This command implies the --drop-if-no-change option, so we avoid creating unnecessary snapshots β€” because a lot of the SUSEConnect options are read-only or only need access to /etc anyway. efficient queen πŸ’…

SUSEConnect is always a non-interactive command.

πŸ’« Interactive Package Commands

  • migration arguments β€” on systems registered against the SUSE Customer Center (SCC) or SMT, you can migrate to a new version of the installed products with this option. It calls zypper migration with the given arguments.

These arguments can be any zypper-migration(8) argument, except --root, because transactional-update handles that dynamically itself. don't fight the tool, bestie πŸ™ˆ

  • pkg command arguments β€” calls zypper with the given command and arguments. Those arguments are typically one or more package names, but can be any zypper(8) parameter for the given command, options included. The supported commands are:
    • install, in β€” installs additional software. See the install description in the "Package Management Commands" section of zypper's man page for all available arguments.
    • remove, rm β€” removes installed software. See the remove description in the "Package Management Commands" section of zypper's man page for all available arguments.
    • update, up β€” update selected software. See the update description in the "Update Management Commands" section of zypper's man page for all available arguments.
  • apply-oci --image image source β€” instead of updating the existing system, the given image gets written into the snapshot. Only the root file system will be replaced; the contents of directories such as /etc and /var will be preserved.
⚠️ Warning β€” this command is under development and will change in the future. There are no checks whether the image will boot so far, and the functionality is not available via API / D-Bus yet. literally read the warning, bestie πŸ˜­πŸ’€

🌸 Standalone Commands 🌸

  • rollback [number] β€” sets the default root file system. On a read-only system the root file system gets set directly using btrfs. On read-write systems, snapper(8) rollback is called.

If no snapshot number is given, the current root file system is set as the new default root file system. Otherwise number can be either a snapshot number (as displayed by snapper list) or the word last. last will try to reset to the latest working snapshot. time travel, but make it responsible ⭐

This command can be combined with the apply command to make the snapshot effective immediately. πŸŽ€


✨ OPTIONS ✨

  • --interactive, -i β€” calls zypper in interactive mode, even if the default for this command is non-interactive.
  • --non-interactive, -n β€” calls zypper in non-interactive mode, even if the default for this command is interactive.
  • --continue [number], -c [number] β€” use the given snapshot or, if no number is given, the current default snapshot as a base for the next snapshot. 🧚
  • --no-selfupdate β€” skip checking for newer transactional-update versions.
  • --drop-if-no-change, -d β€” if the action does not produce a change in the underlying file system, the snapshot will be dropped.
  • --quiet β€” don't print warnings and informational messages to stdout when they're generated by transactional-update itself. i.e. when using the run command only the actual output of the command will be shown; for other commands the --quiet option will be appended to the corresponding helper applications if available (like to the zypper command for the Package Commands). shhh 🀫
  • --help, -h β€” display help and exit.
  • --version β€” output version information and exit. πŸ’œ

✨ EXIT STATUS ✨

  • 0 β€” all commands were executed successfully. slay πŸŽ‰
  • 1 β€” one of the commands returned with an error. Because of that, a potential new snapshot has been deleted again. 😭
  • 2 β€” the apply command was not successful. If called together with other commands, those commands were completed successfully, but the new default snapshot will not be set in the live system. 🫠

⚠️ IMPORTANT ⚠️

okay bestie, this part is the please read this part, no skipping πŸ™

  • Only RPMs that are fully part of the root filesystem and /etc can be updated. Like, that's the whole radius of the vibe. If it's not in there, it's not getting updated by this. πŸ’…
  • There's also limited handling for adding files and directories to /var β€” but modifying existing files (think: migrating databases, the classic) is supposed to be handled by systemd jobs at startup. The manpage literally points you at the initial configuration and deployment section of the packaging guidelines for that one (that's note [1] down below, iykyk).
🫢 real talk: since all the changes to the root filesystem get lost after creating the snapshot for the update, you should reboot as fast as possible after the update finishes. Like, don't go make a snack first. Reboot. πŸƒβ€β™€οΈπŸ’¨
  • And this one is huge, so listen up: every time transactional-update creates a new snapshot, it's based on the currently running system. So if you call transactional-update multiple times without rebooting, none of the changes from the previous snapshot get included β€” which effectively discards all previous changes. 😭 Gone. Poof.

The two exceptions, and only these two, are: passing --continue to explicitly continue a previous snapshot, or when apply was called previously. That's it. Those are the loopholes. πŸŽ€


πŸ‘€ SEE ALSO

the sister pages and the reading list, go off πŸ‘‘


πŸ’– AUTHOR

This icon right here wrote it: Thorsten Kukuk <kukuk@suse.com> β€” thank you for your service, king πŸ‘‘πŸ«Ά


πŸ“Ž NOTES

  1. initial configuration and deployment section of the packaging guidelines β€” literally the exact anchor, copy it carefully bestie: https://en.opensuse.org/openSUSE:Packaging_guidelines#systemd_services_.28as_a_sample_see_mariadb_package.29
  2. The Transactional Update Guide β€” your homework, fr fr: https://kubic.opensuse.org/documentation/transactional-update-guide/transactional-update.html

and that's the whole page, you made it to the end bestie!! πŸŽ‰πŸ’œ this beaut is transactional-update, dated 09/04/2026, and it's living in section TRANSACTIONAL-UPDAT(8) of the manual β€” go forth and snapshot responsibly, mwah πŸ’‹βœ¨πŸŒˆ

πŸ“¦ where this page comes from