diff --git a/README.md b/README.md index 8ef133c..9ce1f3e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Universal Blue Update -Small update program written in python intended for use in Universal Blue, executes update scripts/tasks placed in `/etc/ublue-update.d` (make sure each script has exec perms) +Small update program written in python intended for use in Universal Blue that uses [`topgrade`](https://github.com/topgrade-rs/topgrade) for executing updates. Includes systemd timers and services for auto update @@ -75,20 +75,15 @@ $ journalctl -exu 'ublue-update.service' # Configuration ## Update Scripts -Update scripts are separated into two directories inside of `/etc/ublue-update.d` +Update scripts are separated into two files inside of `/usr/share/ublue-update` -### `/etc/ublue-update.d/user` +### `/usr/share/ublue-update/topgrade-system.toml` +Topgrade config ran as root, handles rpm-ostree and flatpaks. -Update scripts are ran as user. Scripts included: - - per-user flatpak update scripts (uninstalling unused deps and repairing flatpak install for maintenence) - - distrobox update script - - fleek update script +### `/usr/share/ublue-update/topgrade-user.toml` +Topgrade config ran as user, handles flatpaks and distrobox containers. -### `/etc/ublue-update.d/system` - -Update scripts are ran as root, these updates are meant to be system-wide. Scripts included: - - OS update script (depends on [`rpm-ostree`](https://github.com/coreos/rpm-ostree)) - - system-wide flatpak update scripts (uninstalling unused deps and repairing flatpak install for maintenence) +See [`topgrade`](https://github.com/topgrade-rs/topgrade)'s GitHub for configuring these files. ## Location diff --git a/files/etc/ublue-update.d/system/00-system-update.py b/files/etc/ublue-update.d/system/00-system-update.py deleted file mode 100755 index 205b8fa..0000000 --- a/files/etc/ublue-update.d/system/00-system-update.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/python3 - -from subprocess import run -from json import loads, load -from json.decoder import JSONDecodeError -from pathlib import Path - -import os - - -def check_for_rebase(): - # initialize variables - default_image_ref = [] - current_image_ref = [] - default_image_tag = "" - image_tag = "" - - try: - with open("/usr/share/ublue-os/image-info.json") as f: - image_info = load(f) - default_image_ref = image_info["image-ref"].split(":") - default_image_tag = image_info["image-tag"] - except (FileNotFoundError, KeyError): - print("uBlue image info file does not exist") - return False, "" - - # Branch away from the default tag when one is set - branch_file = Path("/var/ublue-update/branch") - if branch_file.exists(): - with branch_file.open() as f: - branch = f.readline() - branch_file.unlink() - if branch: - return ( - True, - f"{default_image_ref[0]}:{default_image_ref[1]}:{default_image_ref[2]}:{branch}", - ) - - status_cmd = [ - "rpm-ostree", - "status", - "--pending-exit-77", - "-b", - "--json", - ] - status_out = run(status_cmd, capture_output=True) - if status_out.returncode != 0: - print(status_out.stdout.decode("utf-8")) - return False, "" - - try: - current_image_ref = ( - loads(status_out.stdout)["deployments"][0]["container-image-reference"] - .replace( - "ostree-unverified-registry:", "ostree-unverified-image:docker://" - ) # replace shorthand - .split(":") - ) - # if the same ref as image-info.json then skip rebase - if current_image_ref[:-1] == default_image_ref: - return False, "" - except (JSONDecodeError, KeyError, IndexError): - print("unable to parse JSON output") - print(status_out.stdout.decode("utf-8")) - return False, "" - - image_tag = default_image_tag - try: - # if we are on an offline ISO installation - # rebase to image-info.json defaults - if current_image_ref[2] == "/var/ublue-os/image": - return ( - True, - f"{default_image_ref[0]}:{default_image_ref[1]}:{default_image_ref[2]}:{default_image_tag}", - ) - - # if current installation doesn't match image-info.json - # skip rebase to be safe - if current_image_ref[2] != default_image_ref[2]: - return False, "" - - # We want to rebase so preserve image tag when rebasing unsigned - if current_image_ref[2] == default_image_ref[2]: - image_tag = current_image_ref[3] - except IndexError: - print("unable to get image tag from current deployment!") - - return ( - True, - f"{default_image_ref[0]}:{default_image_ref[1]}:{default_image_ref[2]}:{image_tag}", - ) - - -if __name__ == "__main__": - rpm_ostree = os.access("/usr/bin/rpm-ostree", os.X_OK) - if not rpm_ostree: - print("system isn't managed by rpm-ostree") - os._exit(1) - rebase, image_ref = check_for_rebase() - if rebase: - rebase_cmd = ["rpm-ostree", "rebase", image_ref] - print(image_ref) - rebase_out = run(rebase_cmd, capture_output=True) - if rebase_out.returncode == 0: - os._exit(0) # rebase sucessful - else: - print("rebase failed!, command output:") - print(rebase_out.stdout.decode("utf-8")) - update_cmd = ["/usr/bin/topgrade", "--config", "/etc/ublue-update/topgrade-system.toml"] - update_out = run(update_cmd, capture_output=True) - if update_out.returncode != 0: - print( - f"topgrade returned code {update_out.returncode}, program output:" - ) - print(update_out.stdout.decode("utf-8")) - os._exit(update_out.returncode) diff --git a/files/usr/etc/polkit-1/rules.d/ublue-update.rules b/files/usr/share/polkit-1/rules.d/ublue-update.rules similarity index 100% rename from files/usr/etc/polkit-1/rules.d/ublue-update.rules rename to files/usr/share/polkit-1/rules.d/ublue-update.rules diff --git a/files/usr/etc/ublue-update/topgrade-system.toml b/files/usr/share/ublue-update/topgrade-system.toml similarity index 100% rename from files/usr/etc/ublue-update/topgrade-system.toml rename to files/usr/share/ublue-update/topgrade-system.toml diff --git a/files/usr/etc/ublue-update/topgrade-user.toml b/files/usr/share/ublue-update/topgrade-user.toml similarity index 100% rename from files/usr/etc/ublue-update/topgrade-user.toml rename to files/usr/share/ublue-update/topgrade-user.toml diff --git a/src/ublue_update/cli.py b/src/ublue_update/cli.py index bbc5d57..19724b4 100644 --- a/src/ublue_update/cli.py +++ b/src/ublue_update/cli.py @@ -86,30 +86,6 @@ def hardware_inhibitor_checks_failed( raise Exception(f"update failed to pass checks: \n - {exception_log}") -def run_update_scripts(root_dir: str): - for root, dirs, files in os.walk(root_dir): - for file in files: - full_path = root_dir + str(file) - executable = os.access(full_path, os.X_OK) - if executable: - log.info(f"Running update script: {full_path}") - out = subprocess.run( - [full_path], - capture_output=True, - ) - if out.returncode != 0: - log.error( - f"{full_path} returned error code: {out.returncode}, program output:" # noqa: E501 - ) - log.error(out.stdout.decode("utf-8")) - notify( - "System Updater", - f"Error in update script: {file}, check logs for more info", - ) - else: - log.info(f"could not execute file {full_path}") - - def run_updates(system, system_update_available): process_uid = os.getuid() filelock_path = "/run/ublue-update.lock" @@ -120,7 +96,6 @@ def run_updates(system, system_update_available): fd = acquire_lock(filelock_path) if fd is None: raise Exception("updates are already running for this user") - root_dir = "/etc/ublue-update.d" """Wait on any existing transactions to complete before updating""" transaction_wait() @@ -139,7 +114,25 @@ def run_updates(system, system_update_available): if system: users = [] - run_update_scripts(f"{root_dir}/system/") + """System""" + out = subprocess.run( + [ + "/usr/bin/topgrade", + "--config", + "/usr/share/ublue-update/topgrade-system.toml", + ], + capture_output=True, + ) + log.debug(out.stdout.decode("utf-8")) + + if out.returncode != 0: + print( + f"topgrade returned code {out.returncode}, program output:" + ) + print(out.stdout.decode("utf-8")) + os._exit(out.returncode) + + """Users""" for user in users: try: xdg_runtime_dir = get_xdg_runtime_dir(user["User"]) @@ -160,7 +153,7 @@ def run_updates(system, system_update_available): f"DBUS_SESSION_BUS_ADDRESS=unix:path={xdg_runtime_dir}/bus", "/usr/bin/topgrade", "--config", - "/etc/ublue-update/topgrade-user.toml", + "/usr/share/ublue-update/topgrade-user.toml", ], capture_output=True, ) diff --git a/ublue-update.spec b/ublue-update.spec index d399034..626a9fc 100644 --- a/ublue-update.spec +++ b/ublue-update.spec @@ -44,14 +44,12 @@ ls ls src black src flake8 src -black files/etc/%{NAME}.d/system/*.py -flake8 files/etc/%{NAME}.d/system/*.py %pyproject_wheel %install %pyproject_install %pyproject_save_files ublue_update -cp -rp files/etc files/usr %{buildroot} +cp -rp files/usr %{buildroot} %pre if [ ! -x /usr/bin/topgrade ] @@ -72,8 +70,8 @@ fi %attr(0644,root,root) %{_exec_prefix}/lib/systemd/system/%{NAME}.timer %attr(0644,root,root) %{_exec_prefix}/lib/systemd/system-preset/00-%{NAME}.preset %attr(0644,root,root) %{_exec_prefix}/etc/%{NAME}/*.toml -%attr(0755,root,root) %{_sysconfdir}/%{NAME}.d/system/* -%attr(0644,root,root) %{_exec_prefix}/etc/polkit-1/rules.d/%{NAME}.rules +%attr(0644,root,root) %{_datadir}/%{NAME}/*.toml +%attr(0644,root,root) %{_datadir}/polkit-1/rules.d/%{NAME}.rules %changelog %autochangelog