Skip to content

Commit

Permalink
Do not notify outdated & EOL VMs if skip-update set
Browse files Browse the repository at this point in the history
Allow users to set special `skip-update` feature for idividual qubes to
suppress Qubes Update systray widget notifications on them.

fixes: QubesOS/qubes-issues#9029
  • Loading branch information
alimirjamali committed Oct 13, 2024
1 parent bab3289 commit a3f61ca
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 47 deletions.
84 changes: 39 additions & 45 deletions qui/tray/updates.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,43 +127,44 @@ def check_vms_needing_update(self):
self.obsolete_vms.clear()
for vm in self.qapp.domains:
try:
updates_available = vm.features.get('updates-available', False)
updated: bool = qui.utils.check_update(vm)
supported: bool = qui.utils.check_support(vm)
except exc.QubesDaemonCommunicationError:
updates_available = False
if updates_available and \
(getattr(vm, 'updateable', False) or vm.klass == 'AdminVM'):
continue
if not updated:
self.vms_needing_update.add(vm)
try:
supported = qui.utils.check_support(vm)
except exc.QubesDaemonCommunicationError:
supported = True
if not supported:
self.obsolete_vms.add(vm.name)

def connect_events(self):
self.dispatcher.add_handler('domain-feature-set:updates-available',
self.feature_set)
self.feature_change)
self.dispatcher.add_handler('domain-feature-delete:updates-available',
self.feature_unset)
self.feature_change)
self.dispatcher.add_handler('domain-feature-set:skip-update',
self.feature_change)
self.dispatcher.add_handler('domain-feature-delete:skip-update',
self.feature_change)
self.dispatcher.add_handler('domain-add', self.domain_added)
self.dispatcher.add_handler('domain-delete', self.domain_removed)
self.dispatcher.add_handler('domain-feature-set:os-eol',
self.feature_set)
self.feature_change)

def domain_added(self, _submitter, _event, vm, *_args, **_kwargs):
def domain_added(self, _submitter, _event, vmname, *_args, **_kwargs):
try:
vm_object = self.qapp.domains[vm]
vm = self.qapp.domains[vmname]
updated: bool = qui.utils.check_update(vm)
supported: bool = qui.utils.check_support(vm)
except exc.QubesException:
# a disposableVM crashed on start
return
try:
updates_available = vm_object.features.get(
'updates-available', False)
except exc.QubesDaemonCommunicationError:
updates_available = False
if updates_available and (getattr(vm_object, 'updateable', False) or
vm_object.klass == 'AdminVM'):
self.vms_needing_update.add(vm_object.name)
return
if not updated:
self.vms_needing_update.add(vm.name)
self.update_indicator_state()
if not supported:
self.obsolete_vms.add(vm)
self.update_indicator_state()

def domain_removed(self, _submitter, _event, vm, *_args, **_kwargs):
Expand All @@ -174,34 +175,27 @@ def domain_removed(self, _submitter, _event, vm, *_args, **_kwargs):
self.obsolete_vms.remove(vm)
self.update_indicator_state()

def feature_unset(self, vm, event, feature, **_kwargs):
def feature_change(self, vm, event, feature, **_kwargs):
# pylint: disable=unused-argument
if vm in self.vms_needing_update:
self.vms_needing_update.remove(vm)
self.update_indicator_state()
try:
updated: bool = qui.utils.check_update(vm)
supported: bool = qui.utils.check_support(vm)
except exc.QubesDaemonCommunicationError:
return

def feature_set(self, vm, event, feature, value, **_kwargs):
# pylint: disable=unused-argument
if feature == 'updates-available':
if value and vm not in self.vms_needing_update and\
getattr(vm, 'updateable', False):
self.vms_needing_update.add(vm)
if not updated and vm not in self.vms_needing_update:
self.vms_needing_update.add(vm)
notification = Gio.Notification.new(
_("New updates are available for {}.").format(vm.name))
notification.set_priority(Gio.NotificationPriority.NORMAL)
self.send_notification(None, notification)
elif updated and vm in self.vms_needing_update:
self.vms_needing_update.remove(vm)

notification = Gio.Notification.new(
_("New updates are available for {}.").format(vm.name))
notification.set_priority(Gio.NotificationPriority.NORMAL)
self.send_notification(None, notification)
elif not value and vm in self.vms_needing_update:
self.vms_needing_update.remove(vm)
elif feature == 'os-eol':
try:
supported = qui.utils.check_support(vm)
except exc.QubesDaemonCommunicationError:
supported = True
if supported and vm.name in self.obsolete_vms:
self.obsolete_vms.remove(vm.name)
elif not supported and vm.name not in self.obsolete_vms:
self.obsolete_vms.add(vm.name)
if not supported and vm not in self.obsolete_vms:
self.obsolete_vms.add(vm.name)
elif supported and vm in self.obsolete_vms:
self.obsolete_vms.remove(vm.name)

self.update_indicator_state()

Expand Down
18 changes: 16 additions & 2 deletions qui/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,25 @@ def run_asyncio_and_show_errors(loop, tasks, name, restart=True):
exit_code = 1
return exit_code

def check_update(vm) -> bool:
"""Return true if the given template/standalone vm is updated or not
updateable or skipped. default returns true"""
if not vm.features.get('updates-available', False):
return True
if not getattr(vm, 'updateable', False):
return True
if bool(vm.features.get('skip-update', False)):
return True
return False

def check_support(vm):
def check_support(vm) -> bool:
"""Return true if the given template/standalone vm is still supported, by
default returns true"""
# first, check if qube itself has known eol
# first, we skip VMs with `skip-update` feature set to true
if bool(vm.features.get('skip-update', False)):
return True

# next, check if qube itself has known eol
eol_string: str = vm.features.get('os-eol', '')

if not eol_string:
Expand Down

0 comments on commit a3f61ca

Please sign in to comment.