Skip to content

Commit

Permalink
vmupdate: add support for nixos
Browse files Browse the repository at this point in the history
  • Loading branch information
evq committed Sep 19, 2024
1 parent fc9e5a1 commit 0799c67
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 10 deletions.
10 changes: 8 additions & 2 deletions vmupdate/agent/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ def main(args=None):
)

log.debug("Notify dom0 about upgrades.")
os.system("/usr/lib/qubes/upgrades-status-notify")
if os_data["os_family"] == "NixOS":
# use non-absolute path since NixOS will configure PATH correctly for us
os.system("upgrades-status-notify")
else:
os.system("/usr/lib/qubes/upgrades-status-notify")

if not args.no_cleanup:
return_code = max(pkg_mng.clean(), return_code)
Expand Down Expand Up @@ -78,9 +82,11 @@ def get_package_manager(os_data, log, log_handler, log_level, no_progress):
from source.dnf.dnf_cli import DNFCLI as PackageManager
elif os_data["os_family"] == "ArchLinux":
from source.pacman.pacman_cli import PACMANCLI as PackageManager
elif os_data["os_family"] == "NixOS":
from source.nixos.nixos_cli import NIXOSCLI as PackageManager
else:
raise NotImplementedError(
"Only Debian, RedHat and ArchLinux based OS is supported.")
"Only Debian, RedHat, ArchLinux, NixOS based OS is supported.")

requirements = {}
for plugin in plugins.entrypoints:
Expand Down
13 changes: 8 additions & 5 deletions vmupdate/agent/source/common/package_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def _print_changes(self, changes):
if changes["installed"]:
for pkg in changes["installed"]:
result.out += self._print_to_string(
pkg, changes["installed"][pkg])
pkg, ", ".join(changes["installed"][pkg]))
else:
result.out += self._print_to_string("None")

Expand All @@ -227,17 +227,17 @@ def _print_changes(self, changes):
for pkg in changes["updated"]:
result.out += self._print_to_string(
pkg,
str(changes["updated"][pkg]["old"])[2:-2]
", ".join((changes["updated"][pkg]["old"]))
+ " -> " +
str(changes["updated"][pkg]["new"])[2:-2])
", ".join((changes["updated"][pkg]["new"]))
else:
result.out += self._print_to_string("None")

result.out += self._print_to_string("Removed packages:")
if changes["removed"]:
for pkg in changes["removed"]:
result.out += self._print_to_string(
pkg, changes["removed"][pkg])
pkg, ", ".join(changes["removed"][pkg]))
else:
result.out += self._print_to_string("None")
return result
Expand Down Expand Up @@ -276,7 +276,10 @@ def upgrade_internal(self, remove_obsolete: bool) -> ProcessResult:
Just run upgrade via CLI.
"""
cmd = [self.package_manager,
"--noconfirm" if self.package_manager == "pacman" else "-y",
*(
["--noconfirm"] if self.package_manager == "pacman"
else [] if self.package_manager == "qubes-nixos-rebuild" else "-y"
),
*self.get_action(remove_obsolete)]

return self.run_cmd(cmd)
Expand Down
18 changes: 18 additions & 0 deletions vmupdate/agent/source/nixos/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# coding=utf-8
#
# The Qubes OS Project, http://www.qubes-os.org
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
70 changes: 70 additions & 0 deletions vmupdate/agent/source/nixos/nixos_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# coding=utf-8
#
# The Qubes OS Project, http://www.qubes-os.org
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.

from typing import List, Dict

from source.common.package_manager import PackageManager
from source.common.process_result import ProcessResult


class NIXOSCLI(PackageManager):
def __init__(self, log_handler, log_level):
super().__init__(log_handler, log_level)
self.package_manager = "qubes-nixos-rebuild"

def refresh(self, hard_fail: bool) -> ProcessResult:
"""
Use package manager to refresh available packages.
Note: Is a no-op in NixOS because the qubes-nixos-rebuild
wrapper takes care of it, and having just sync could cause problems.
:return: (exit_code, stdout, stderr)
"""
cmd = ["true"]
return self.run_cmd(cmd)

def get_packages(self) -> Dict[str, List[str]]:
"""
Use nix to return the installed packages and their versions.
"""

cmd = ["qubes-nixos-get-packages"]
# EXAMPLE OUTPUT:
# qubes-core-agent-linux: ∅ → 4.3.5, +1413.6 KiB
# python3: ∅ → 3.11.9, 3.12.4, +229814.3 KiB
# dns-root-data: ∅ → 2024-06-20

result = self.run_cmd(cmd, realtime=False)

packages: Dict[str, List[str]] = {}
for line in result.out.splitlines():
package, info = line.split(":", 1)
versions = info.lstrip("∅ → ").split(", ")
for version in versions:
if not version.startswith("+"):
packages.setdefault(package, []).append(version)

return packages

def get_action(self, remove_obsolete) -> List[str]:
"""
qubes-nixos-rebuild will handle obsoletions itself
"""
return []
3 changes: 3 additions & 0 deletions vmupdate/agent/source/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ def get_os_data(logger: Optional = None) -> Dict[str, Any]:
if 'arch' in family:
data["os_family"] = 'ArchLinux'

if "nixos" in family:
data["os_family"] = "NixOS"

return data


Expand Down
9 changes: 6 additions & 3 deletions vmupdate/qube_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class QubeConnection:
stop the qube if it was started by this connection.
"""

PYTHON_PATH = "/usr/bin/python3"
PYTHON_PATH = "/usr/bin"

def __init__(
self,
Expand Down Expand Up @@ -162,8 +162,11 @@ def run_entrypoint(
result = self._run_shell_command_in_qube(self.qube, command)

# run entrypoint
command = [QubeConnection.PYTHON_PATH, entrypoint_path,
*AgentArgs.to_cli_args(agent_args)]
command = ["sh", "-c", " ".join(
["env", f"PATH=${QubeConnection.PYTHON_PATH}:$PATH",
"python3", entrypoint_path,
*AgentArgs.to_cli_args(agent_args)])]

result += self._run_shell_command_in_qube(
self.qube, command, show=self.show_progress)

Expand Down

0 comments on commit 0799c67

Please sign in to comment.