diff --git a/src/middlewared/middlewared/alert/source/applications.py b/src/middlewared/middlewared/alert/source/applications.py index 9a18a8c539f3d..36134c888b7de 100644 --- a/src/middlewared/middlewared/alert/source/applications.py +++ b/src/middlewared/middlewared/alert/source/applications.py @@ -29,7 +29,7 @@ async def delete(self, alerts, query): return [] -class ChartReleaseUpdateAlertClass(AlertClass, OneShotAlertClass): +class AppUpdateAlertClass(AlertClass, OneShotAlertClass): deleted_automatically = False category = AlertCategory.APPLICATIONS @@ -38,7 +38,7 @@ class ChartReleaseUpdateAlertClass(AlertClass, OneShotAlertClass): text = 'An update is available for "%(name)s" application.' async def create(self, args): - return Alert(ChartReleaseUpdateAlertClass, args, _key=args['name']) + return Alert(AppUpdateAlertClass, args, _key=args['name']) async def delete(self, alerts, query): return list(filter( diff --git a/src/middlewared/middlewared/plugins/apps/crud.py b/src/middlewared/middlewared/plugins/apps/crud.py index ed6c1a1419748..9c5613d51dc9f 100644 --- a/src/middlewared/middlewared/plugins/apps/crud.py +++ b/src/middlewared/middlewared/plugins/apps/crud.py @@ -339,6 +339,8 @@ def delete_internal(self, job, app_name, app_config, options): if options.get('send_event', True): self.middleware.send_event('app.query', 'REMOVED', id=app_name) + + self.middleware.call_sync('alert.oneshot_delete', 'AppUpdate', app_name) job.set_progress(100, f'Deleted {app_name!r} app') return True diff --git a/src/middlewared/middlewared/plugins/apps/upgrade.py b/src/middlewared/middlewared/plugins/apps/upgrade.py index 19787c84fc11f..1ccb509d5aeed 100644 --- a/src/middlewared/middlewared/plugins/apps/upgrade.py +++ b/src/middlewared/middlewared/plugins/apps/upgrade.py @@ -96,7 +96,13 @@ def upgrade(self, job, app_name, options): ) job.set_progress(100, 'Upgraded app successfully') - return self.middleware.call_sync('app.get_instance', app_name) + app = self.middleware.call_sync('app.get_instance', app_name) + if app['upgrade_available'] is False: + # We have this conditional for the case if user chose not to upgrade to latest version + # and jump to some intermediate version which is not latest + self.middleware.call_sync('alert.oneshot_delete', 'AppUpdate', app_name) + + return app @accepts( Str('app_name'), @@ -168,3 +174,16 @@ async def get_versions(self, app, options): 'versions': app_details['versions'], 'latest_version': app_details['versions'][get_latest_version_from_app_versions(app_details['versions'])], } + + @private + async def clear_upgrade_alerts_for_all(self): + for app in await self.middleware.call('app.query'): + await self.middleware.call('alert.oneshot_delete', 'AppUpdate', app['id']) + + @private + async def check_upgrade_alerts(self): + for app in await self.middleware.call('app.query'): + if app['upgrade_available']: + await self.middleware.call('alert.oneshot_create', 'AppUpdate', {'name': app['id']}) + else: + await self.middleware.call('alert.oneshot_delete', 'AppUpdate', app['id']) diff --git a/src/middlewared/middlewared/plugins/catalog/sync.py b/src/middlewared/middlewared/plugins/catalog/sync.py index 0c7c6c3aa7fe8..c30274341ec8e 100644 --- a/src/middlewared/middlewared/plugins/catalog/sync.py +++ b/src/middlewared/middlewared/plugins/catalog/sync.py @@ -47,6 +47,7 @@ async def sync(self, job): await self.middleware.call('alert.oneshot_delete', 'CatalogSyncFailed', OFFICIAL_LABEL) job.set_progress(100, f'Synced {OFFICIAL_LABEL!r} catalog') self.SYNCED = True + self.middleware.create_task(self.middleware.call('app.check_upgrade_alerts')) @private def update_git_repository(self, location, repository, branch): diff --git a/src/middlewared/middlewared/plugins/docker/state_management.py b/src/middlewared/middlewared/plugins/docker/state_management.py index 1912f03ed3499..795df7ca9a703 100644 --- a/src/middlewared/middlewared/plugins/docker/state_management.py +++ b/src/middlewared/middlewared/plugins/docker/state_management.py @@ -1,4 +1,4 @@ -from middlewared.service import CallError, periodic, Service +from middlewared.service import CallError, periodic, Service, private from .state_utils import APPS_STATUS, Status, STATUS_DESCRIPTIONS @@ -98,7 +98,6 @@ async def periodic_check(self): docker_config = await self.middleware.call('docker.config') if docker_config['enable_image_updates']: self.middleware.create_task(self.middleware.call('app.image.op.check_update')) - # TODO: Add app upgrade alerts async def _event_system_ready(middleware, event_type, args): diff --git a/src/middlewared/middlewared/plugins/docker/state_setup.py b/src/middlewared/middlewared/plugins/docker/state_setup.py index 966abc6810ccc..3e9e27f931e87 100644 --- a/src/middlewared/middlewared/plugins/docker/state_setup.py +++ b/src/middlewared/middlewared/plugins/docker/state_setup.py @@ -71,6 +71,7 @@ async def status_change(self): await self.create_update_docker_datasets(config['dataset']) await self.middleware.call('docker.state.start_service') + self.middleware.create_task(self.middleware.call('docker.state.periodic_check')) @private def move_conflicting_dir(self, ds_name): diff --git a/src/middlewared/middlewared/plugins/docker/update.py b/src/middlewared/middlewared/plugins/docker/update.py index 65c81e79f9622..c38e1a8dab570 100644 --- a/src/middlewared/middlewared/plugins/docker/update.py +++ b/src/middlewared/middlewared/plugins/docker/update.py @@ -83,6 +83,10 @@ async def do_update(self, job, data): ) if old_config != config: + if config['pool'] != old_config['pool']: + # We want to clear upgrade alerts for apps at this point + await self.middleware.call('app.clear_upgrade_alerts_for_all') + if any(config[k] != old_config[k] for k in ('pool', 'address_pools')): job.set_progress(20, 'Stopping Docker service') try: