Skip to content

Commit f681cca

Browse files
committed
vmupdate: add support for nixos
1 parent fc9e5a1 commit f681cca

File tree

6 files changed

+113
-10
lines changed

6 files changed

+113
-10
lines changed

vmupdate/agent/entrypoint.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ def main(args=None):
3232
)
3333

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

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

8591
requirements = {}
8692
for plugin in plugins.entrypoints:

vmupdate/agent/source/common/package_manager.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def _print_changes(self, changes):
218218
if changes["installed"]:
219219
for pkg in changes["installed"]:
220220
result.out += self._print_to_string(
221-
pkg, changes["installed"][pkg])
221+
pkg, ", ".join(changes["installed"][pkg]))
222222
else:
223223
result.out += self._print_to_string("None")
224224

@@ -227,17 +227,17 @@ def _print_changes(self, changes):
227227
for pkg in changes["updated"]:
228228
result.out += self._print_to_string(
229229
pkg,
230-
str(changes["updated"][pkg]["old"])[2:-2]
230+
", ".join((changes["updated"][pkg]["old"]))
231231
+ " -> " +
232-
str(changes["updated"][pkg]["new"])[2:-2])
232+
", ".join((changes["updated"][pkg]["new"]))
233233
else:
234234
result.out += self._print_to_string("None")
235235

236236
result.out += self._print_to_string("Removed packages:")
237237
if changes["removed"]:
238238
for pkg in changes["removed"]:
239239
result.out += self._print_to_string(
240-
pkg, changes["removed"][pkg])
240+
pkg, ", ".join(changes["removed"][pkg]))
241241
else:
242242
result.out += self._print_to_string("None")
243243
return result
@@ -276,7 +276,10 @@ def upgrade_internal(self, remove_obsolete: bool) -> ProcessResult:
276276
Just run upgrade via CLI.
277277
"""
278278
cmd = [self.package_manager,
279-
"--noconfirm" if self.package_manager == "pacman" else "-y",
279+
*(
280+
["--noconfirm"] if self.package_manager == "pacman"
281+
else [] if self.package_manager == "qubes-nixos-rebuild" else "-y"
282+
),
280283
*self.get_action(remove_obsolete)]
281284

282285
return self.run_cmd(cmd)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# coding=utf-8
2+
#
3+
# The Qubes OS Project, http://www.qubes-os.org
4+
#
5+
# This program is free software; you can redistribute it and/or
6+
# modify it under the terms of the GNU General Public License
7+
# as published by the Free Software Foundation; either version 2
8+
# of the License, or (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License
16+
# along with this program; if not, write to the Free Software
17+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18+
# USA.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# coding=utf-8
2+
#
3+
# The Qubes OS Project, http://www.qubes-os.org
4+
#
5+
# This program is free software; you can redistribute it and/or
6+
# modify it under the terms of the GNU General Public License
7+
# as published by the Free Software Foundation; either version 2
8+
# of the License, or (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License
16+
# along with this program; if not, write to the Free Software
17+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18+
# USA.
19+
20+
from typing import List, Dict
21+
22+
from source.common.package_manager import PackageManager
23+
from source.common.process_result import ProcessResult
24+
25+
26+
class NIXOSCLI(PackageManager):
27+
def __init__(self, log_handler, log_level):
28+
super().__init__(log_handler, log_level)
29+
self.package_manager = "qubes-nixos-rebuild"
30+
31+
def refresh(self, hard_fail: bool) -> ProcessResult:
32+
"""
33+
Use package manager to refresh available packages.
34+
35+
Note: Is a no-op in NixOS because the qubes-nixos-rebuild
36+
wrapper takes care of it, and having just sync could cause problems.
37+
38+
:return: (exit_code, stdout, stderr)
39+
"""
40+
cmd = ["true"]
41+
return self.run_cmd(cmd)
42+
43+
def get_packages(self) -> Dict[str, List[str]]:
44+
"""
45+
Use nix to return the installed packages and their versions.
46+
"""
47+
48+
cmd = ["qubes-nixos-get-packages"]
49+
# EXAMPLE OUTPUT:
50+
# qubes-core-agent-linux: ∅ → 4.3.5, +1413.6 KiB
51+
# python3: ∅ → 3.11.9, 3.12.4, +229814.3 KiB
52+
# dns-root-data: ∅ → 2024-06-20
53+
54+
result = self.run_cmd(cmd, realtime=False)
55+
56+
packages: Dict[str, List[str]] = {}
57+
for line in result.out.splitlines():
58+
package, info = line.split(":", 1)
59+
versions = info.lstrip("∅ → ").split(", ")
60+
for version in versions:
61+
if not version.startswith("+"):
62+
packages.setdefault(package, []).append(version)
63+
64+
return packages
65+
66+
def get_action(self, remove_obsolete) -> List[str]:
67+
"""
68+
qubes-nixos-rebuild will handle obsoletions itself
69+
"""
70+
return []

vmupdate/agent/source/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ def get_os_data(logger: Optional = None) -> Dict[str, Any]:
6565
if 'arch' in family:
6666
data["os_family"] = 'ArchLinux'
6767

68+
if "nixos" in family:
69+
data["os_family"] = "NixOS"
70+
6871
return data
6972

7073

vmupdate/qube_connection.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class QubeConnection:
4545
stop the qube if it was started by this connection.
4646
"""
4747

48-
PYTHON_PATH = "/usr/bin/python3"
48+
PYTHON_PATH = "/usr/bin"
4949

5050
def __init__(
5151
self,
@@ -162,8 +162,11 @@ def run_entrypoint(
162162
result = self._run_shell_command_in_qube(self.qube, command)
163163

164164
# run entrypoint
165-
command = [QubeConnection.PYTHON_PATH, entrypoint_path,
166-
*AgentArgs.to_cli_args(agent_args)]
165+
command = ["sh", "-c", " ".join(
166+
["env", f"PATH=${QubeConnection.PYTHON_PATH}:$PATH",
167+
"python3", entrypoint_path,
168+
*AgentArgs.to_cli_args(agent_args)])]
169+
167170
result += self._run_shell_command_in_qube(
168171
self.qube, command, show=self.show_progress)
169172

0 commit comments

Comments
 (0)