Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/pr/189'
Browse files Browse the repository at this point in the history
* origin/pr/189:
  updater: fix showing output
  updater: handle nothing to do
  updater: fix parsing `--update-if-stale`
  • Loading branch information
marmarek committed Apr 26, 2024
2 parents b16a878 + 1b1e9b4 commit 6ca64bd
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 35 deletions.
61 changes: 38 additions & 23 deletions qui/updater/intro_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class IntroPage:
"""
First content page of updater.
Show the list of updatable vms with an update info.
Show the list of updatable vms with update info.
"""

def __init__(self, builder, log, next_button):
Expand Down Expand Up @@ -86,7 +86,7 @@ def __init__(self, builder, log, next_button):
))

def populate_vm_list(self, qapp, settings):
"""Adds to list any updatable vms with an update info."""
"""Adds to list any updatable vms with update info."""
self.log.debug("Populate update list")
self.list_store = ListWrapper(
UpdateRowWrapper, self.vm_list.get_model())
Expand All @@ -113,16 +113,14 @@ def refresh_update_list(self, update_if_stale):
if not self.active:
return

output = subprocess.check_output(
['qubes-vm-update', '--dry-run',
'--update-if-stale', str(update_if_stale)])
cmd = ['qubes-vm-update', '--dry-run',
'--update-if-stale', str(update_if_stale)]

to_update = [
vm_name.strip() for vm_name
in output.decode().split("\n", maxsplit=1)[0]
.split(":", maxsplit=1)[1].split(",")]
to_update = self._get_stale_qubes(cmd)

for row in self.list_store:
if row.vm.name == 'dom0':
continue
row.updates_available = bool(row.vm.name in to_update)

def get_vms_to_update(self) -> ListWrapper:
Expand Down Expand Up @@ -162,7 +160,7 @@ def on_header_toggled(self, _emitter):
Cycle between selection of:
<1> vms with `updates_available` (YES)
<2> <1> + vms no checked for updates for a while (YES and MAYBE)
<3> all vms (YES , MAYBE and NO)
<3> all vms (YES, MAYBE and NO)
<4> no vm. (nothing)
If the user has selected any vms that do not match the defined states,
Expand All @@ -176,7 +174,7 @@ def select_rows(self):
row.selected = row.updates_available \
in self.head_checkbox.allowed

def select_rows_ignoring_conditions(self, cliargs):
def select_rows_ignoring_conditions(self, cliargs, dom0):
cmd = ['qubes-vm-update', '--dry-run']

args = [a for a in dir(cliargs) if not a.startswith("_")]
Expand All @@ -192,31 +190,48 @@ def select_rows_ignoring_conditions(self, cliargs):
if not vms_without_dom0:
continue
value = ",".join(vms_without_dom0)
cmd.extend((f"--{arg.replace('_', '-')}", str(value)))
cmd.append(f"--{arg.replace('_', '-')}")
if isinstance(value, str):
cmd.append(value)

if not cmd[2:]:
to_update = set()
else:
to_update = set()
if cmd[2:]:
to_update = self._get_stale_qubes(cmd)

to_update = self._handle_cli_dom0(dom0, to_update, cliargs)

for row in self.list_store:
row.selected = row.name in to_update

def _get_stale_qubes(self, cmd):
try:
self.log.debug("Run command %s", " ".join(cmd))
output = subprocess.check_output(cmd)
self.log.debug("Command returns: %s", output.decode())

to_update = {
vm_name.strip()
for line in output.decode().split("\n", maxsplit=1)
for vm_name in line.split(":", maxsplit=1)[1].split(",")
return {
vm_name.strip() for vm_name
in output.decode().split("\n", maxsplit=1)[0]
.split(":", maxsplit=1)[1].split(",")
}
except subprocess.CalledProcessError as err:
if err.returncode != 100:
raise err
return set()

# handle dom0
@staticmethod
def _handle_cli_dom0(dom0, to_update, cliargs):
if not cliargs.targets and not cliargs.all:
if bool(dom0.features.get(
'updates-available', False)):
to_update.add('dom0')
if cliargs.dom0 or cliargs.all:
to_update.add("dom0")
if cliargs.targets and "dom0" in cliargs.targets.split(","):
to_update.add("dom0")
if cliargs.skip and "dom0" in cliargs.skip.split(","):
to_update = to_update.difference({"dom0"})

for row in self.list_store:
row.selected = row.name in to_update
return to_update


class UpdateRowWrapper(RowWrapper):
Expand Down
2 changes: 1 addition & 1 deletion qui/updater/progress_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def update_admin_vm(self, admins):
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
_stdout, stderr = check_updates.communicate()
if check_updates.returncode != 100:
GLib.idle_add(admin.append_text_view, stderr)
GLib.idle_add(admin.append_text_view, stderr.decode())
if check_updates.returncode != 0:
GLib.idle_add(admin.set_status, UpdateStatus.Error)
else:
Expand Down
29 changes: 18 additions & 11 deletions qui/updater/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def __init__(self, qapp, cliargs):
)
self.qapp = qapp
self.primary = False
self.do_nothing = False
self.connect("activate", self.do_activate)
self.cliargs = cliargs

Expand All @@ -55,11 +56,22 @@ def __init__(self, qapp, cliargs):

def do_activate(self, *_args, **_kwargs):
if not self.primary:
self.log.debug("Primary activation")
self.perform_setup()
self.primary = True
self.hold()
else:
self.main_window.present()
self.log.debug("Secondary activation")
if self.do_nothing:
show_dialog_with_icon(
None, l("Quit"),
l("Nothing to do."),
buttons=RESPONSES_OK,
icon_name="check_yes"
)
self.window_close()
else:
self.main_window.present()

def perform_setup(self, *_args, **_kwargs):
self.log.debug("Setup")
Expand Down Expand Up @@ -157,15 +169,9 @@ def cell_data_func(_column, cell, model, it, data):
if skip_intro_if_args(self.cliargs):
self.log.info("Skipping intro page.")
self.intro_page.select_rows_ignoring_conditions(
cliargs=self.cliargs)
cliargs=self.cliargs, dom0=self.qapp.domains['dom0'])
if len(self.intro_page.get_vms_to_update()) == 0:
show_dialog_with_icon(
None, l("Quit"),
l("Nothing to do."),
buttons=RESPONSES_OK,
icon_name="qubes-info"
)
self.main_window.close()
self.do_nothing = True
return
self.next_clicked(None, skip_intro=True)
else:
Expand All @@ -174,6 +180,7 @@ def cell_data_func(_column, cell, model, it, data):
width = self.intro_page.vm_list.get_preferred_width().natural_width
self.main_window.resize(width + 50, int(width * 1.2))
self.main_window.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
# return 0

def open_settings_window(self, _emitter):
self.settings.show()
Expand Down Expand Up @@ -268,8 +275,8 @@ def parse_args(args):
group.add_argument('--targets', action='store',
help='Comma separated list of VMs to target')
group.add_argument('--all', action='store_true',
help='Target all non-disposable VMs (TemplateVMs and '
'AppVMs)')
help='Target all updatable VMs (AdminVM, '
'TemplateVMs and StandaloneVMs)')
group.add_argument('--update-if-stale', action='store',
help='Target all TemplateVMs with known updates or for '
'which last update check was more than N days '
Expand Down

0 comments on commit 6ca64bd

Please sign in to comment.