def error_handling(etype, exc, etraceback): if isinstance(exc, (ConnectionFailedSecretFile, )): MODULE.error(str(exc)) error_msg = [ _('Cannot connect to the LDAP service.'), _('The server seems to be lacking a proper password file.'), _('Please check the join state of the machine.') ] raise umcm.UMC_Error('\n'.join(error_msg), status=500) if isinstance(exc, (ConnectionFailedInvalidUserCredentials, )): MODULE.error(str(exc)) error_msg = [ _('Cannot connect to the LDAP service.'), _('The credentials provided were not accepted.'), _('This may be solved by simply logging out and in again.'), _('Maybe your password changed during the session.') ] raise umcm.UMC_Error('\n'.join(error_msg), status=500) if isinstance(exc, (ConnectionFailedInvalidMachineCredentials, )): MODULE.error(str(exc)) error_msg = [ _('Cannot connect to the LDAP service.'), _('The credentials provided were not accepted.'), _('This may be solved by simply logging out and in again.'), _('Maybe the machine password changed during the session.') ] raise umcm.UMC_Error('\n'.join(error_msg), status=500) if isinstance(exc, (ConnectionFailedServerDown, )): MODULE.error(str(exc)) raise LDAP_ServerDown() if isinstance(exc, (Abort, SystemError, AppcenterServerContactFailed)): MODULE.error(str(exc)) raise umcm.UMC_Error(str(exc), status=500)
def _remote_appcenter(self, host, function=None): if host is None: raise ValueError('Cannot connect to None') if not host.endswith('.%s' % self.ucr.get('domainname')): raise ValueError('Only connect to FQDNs within the domain') info = get_action('info') opts = {'version': info.get_ucs_version()} if function is not None: opts['function'] = function try: client = Client(host, self.username, self.password) response = client.umc_command('appcenter/version2', opts) except (HTTPError) as exc: raise umcm.UMC_Error( _('Problems connecting to {0} ({1}). Please update {0}!'). format(host, exc.message)) except (ConnectionError, Exception) as exc: raise umcm.UMC_Error( _('Problems connecting to {} ({}).').format(host, str(exc))) err_msg = _( 'The App Center version of the this host ({}) is not compatible with the version of {} ({})' ).format(opts['version'], host, response.result.get('version')) # i guess this is kind of bad if response.status != 200: raise umcm.UMC_Error(err_msg) # remote says he is not compatible if response.result.get('compatible', True) is False: raise umcm.UMC_Error(err_msg) # i'm not compatible if not info.is_compatible(response.result.get('version')): raise umcm.UMC_Error(err_msg) return client
def suggestions(self, version): try: cache = AppCenterCache.build(server=default_server()) cache_file = cache.get_cache_file('.suggestions.json') with open(cache_file) as fd: json = load(fd) except (EnvironmentError, ValueError): raise umcm.UMC_Error(_('Could not load suggestions.')) else: try: return json[version] except (KeyError, AttributeError): raise umcm.UMC_Error(_('Unexpected suggestions data.'))
def packages_invoke(self, request): """ executes an installer action """ packages = request.options.get('packages') function = request.options.get('function') try: if self._working(): # make it multi-tab safe (same session many buttons to be clicked) raise LockError() with self.package_manager.locked(reset_status=True): not_found = [pkg_name for pkg_name in packages if self.package_manager.get_package(pkg_name) is None] self.finished(request.id, {'not_found': not_found}) if not not_found: def _thread(package_manager, function, packages): with package_manager.locked(set_finished=True): with package_manager.no_umc_restart(exclude_apache=True): if function == 'install': package_manager.install(*packages) else: package_manager.uninstall(*packages) def _finished(thread, result): if isinstance(result, BaseException): MODULE.warn('Exception during %s %s: %r' % (function, packages, str(result))) thread = notifier.threads.Simple('invoke', notifier.Callback(_thread, self.package_manager, function, packages), _finished) thread.run() else: self.package_manager.set_finished() # nothing to do, ready to take new commands except LockError: # make it thread safe: another process started a package manager # this module instance already has a running package manager raise umcm.UMC_Error(_('Another package operation is in progress'))
def query(self, quick=False): query_cache_file = '/var/cache/univention-appcenter/umc-query.json' if quick: try: with open(query_cache_file) as fd: return json.load(fd) except (EnvironmentError, ValueError) as exc: MODULE.error('Error returning cached query: %s' % exc) return [] self.update_applications() self.ucr.load() reload_package_manager() list_apps = get_action('list') domain = get_action('domain') apps = list_apps.get_apps() if self.ucr.is_true('appcenter/docker', True): if not self._test_for_docker_service(): raise umcm.UMC_Error( _('The docker service is not running! The App Center will not work properly.' ) + ' ' + _('Make sure docker.io is installed, try starting the service with "service docker start".' )) info = domain.to_dict(apps) with open(query_cache_file, 'w') as fd: json.dump(info, fd) return info
def query(self, quick=False): if not quick: self.update_applications() self.ucr.load() reload_package_manager() list_apps = get_action('list') domain = get_action('domain') apps = list_apps.get_apps() if self.ucr.is_true('appcenter/docker', True): if not self._test_for_docker_service(): raise umcm.UMC_Error(_('The docker service is not running! The App Center will not work properly.') + ' ' + _('Make sure docker.io is installed, try starting the service with "service docker start".')) info = domain.to_dict(apps) if quick: ret = [] for app in info: if app is None: ret.append(None) else: short_info = {} for attr in ['id', 'name', 'vendor', 'maintainer', 'description', 'long_description', 'app_categories', 'end_of_life', 'update_available', 'logo_name', 'is_installed_anywhere', 'is_installed', 'installations', 'rating', 'vote_for_app', 'license', 'license_description', 'candidate_needs_install_permissions']: short_info[attr] = app[attr] ret.append(short_info) return ret else: return info
def enable_docker(self): if self._test_for_docker_service(): ucr_save({'appcenter/docker': 'enabled'}) else: raise umcm.UMC_Error( _('Unable to start the docker service!') + ' ' + _('Make sure docker.io is installed, try starting the service with "service docker start".' ))
def locked(self): try: if self._working(): raise LockError() with package_lock(): yield except LockError: raise umcm.UMC_Error(_('Another package operation is in progress'))
def version(self, version=None): info = get_action('info') ret = info.get_compatibility() if not info.is_compatible(version): raise umcm.UMC_Error( 'The App Center version of the requesting host is not compatible with the version of %s (%s)' % (get_local_fqdn(), ret)) return ret
def update_applications(self): if self.ucr.is_true('appcenter/umc/update/always', True): update = get_action('update') try: update.call() except NetworkError as err: raise umcm.UMC_Error(str(err)) except Abort: pass self.update_applications_done = True
def get_by_component_id(self, component_id): domain = get_action('domain') if isinstance(component_id, list): requested_apps = [Apps().find_by_component_id(cid) for cid in component_id] return domain.to_dict(requested_apps) else: app = Apps().find_by_component_id(component_id) if app: return domain.to_dict([app])[0] else: raise umcm.UMC_Error(_('Could not find an application for %s') % component_id)
def init(self): os.umask( 0o022 ) # umc umask is too restrictive for app center as it creates a lot of files in docker containers self.ucr = ucr_instance() self.update_applications_done = False install_opener(self.ucr) self._is_working = False try: self.package_manager = PackageManager( info_handler=MODULE.process, step_handler=None, error_handler=MODULE.warn, lock=False, ) except SystemError as exc: MODULE.error(str(exc)) raise umcm.UMC_Error(str(exc), status=500) self.package_manager.set_finished( ) # currently not working. accepting new tasks get_package_manager._package_manager = self.package_manager # build cache _update_modules() get_action('list').get_apps() # not initialize here: error prone due to network errors and also kinda slow self._uu = None self._cm = None # in order to set the correct locale locale.setlocale(locale.LC_ALL, str(self.locale)) try: log_to_logfile() except IOError: pass # connect univention.appcenter.log to the progress-method handler = ProgressInfoHandler(self.package_manager) handler.setLevel(logging.INFO) get_base_logger().addHandler(handler) percentage = ProgressPercentageHandler(self.package_manager) percentage.setLevel(logging.DEBUG) get_base_logger().getChild('actions.install.progress').addHandler( percentage) get_base_logger().getChild('actions.upgrade.progress').addHandler( percentage) get_base_logger().getChild('actions.remove.progress').addHandler( percentage)
def invoke_docker(self, function, app, force, values, progress): for setting in app.get_settings(): if isinstance(setting, FileSetting) and not isinstance(setting, PasswordFileSetting): if values.get(setting.name): values[setting.name] = values[setting.name].decode('base64') progress.title = _('%s: Running tests') % app.name serious_problems = False if function == 'upgrade': _original_app = app app = Apps().find_candidate(app) if app is None: # Bug #44384: Under mysterious circumstances, app may be None after the .find_candidate() # This may happen in global App Center when the system the user is logged in has different ini files # than the system the App shall be upgraded on. E.g., in mixed appcenter / appcenter-test environments app = _original_app errors, warnings = {'must_have_candidate': False}, {} else: errors, warnings = app.check(function) can_continue = force # "dry_run" if errors: MODULE.process('Cannot %s %s: %r' % (function, app.id, errors)) serious_problems = True can_continue = False if warnings: MODULE.process('Warning trying to %s %s: %r' % (function, app.id, warnings)) result = { 'serious_problems': serious_problems, 'invokation_forbidden_details': errors, 'invokation_warning_details': warnings, 'can_continue': can_continue, 'software_changes_computed': False, } if can_continue: kwargs = {'noninteractive': True, 'skip_checks': ['shall_have_enough_ram', 'shall_only_be_installed_in_ad_env_with_password_service', 'must_not_have_concurrent_operation'], 'set_vars': values} if function == 'install': progress.title = _('Installing %s') % (app.name,) elif function == 'uninstall': progress.title = _('Uninstalling %s') % (app.name,) elif function == 'upgrade': progress.title = _('Upgrading %s') % (app.name,) action = get_action(function) handler = UMCProgressHandler(progress) handler.setLevel(logging.INFO) action.logger.addHandler(handler) try: result['success'] = action.call(app=app, username=self.username, password=self.password, **kwargs) except AppCenterError as exc: raise umcm.UMC_Error(str(exc), result=dict( display_feedback=True, title='%s %s' % (exc.title, exc.info))) finally: action.logger.removeHandler(handler) return result
def get(self, application): list_apps = get_action('list') domain = get_action('domain') apps = list_apps.get_apps() for app in apps: if app.id == application: break else: app = None if app is None: raise umcm.UMC_Error(_('Could not find an application for %s') % (application,)) return domain.to_dict([app])[0]
def _test_for_docker_service(self): if docker_bridge_network_conflict(): msg = _('A conflict between the system network settings and the docker bridge default network has been detected.') + '\n\n' msg += _('Please either configure a different network for the docker bridge by setting the UCR variable docker/daemon/default/opts/bip to a different network and restart the system,') + ' ' msg += _('or disable the docker support in the AppCenter by setting appcenter/docker to false.') raise umcm.UMC_Error(msg) if not docker_is_running(): MODULE.warn('Docker is not running! Trying to start it now...') call_process(['invoke-rc.d', 'docker', 'start']) if not docker_is_running(): return False return True
def _thread(module, app, function): with module.is_working(): if not dont_remote_install and function != 'remove': self._install_master_packages_on_hosts(app, function) with module.package_manager.no_umc_restart(exclude_apache=True): try: args.dry_run = False args.install_master_packages_remotely = False return action.call_with_namespace(args) except AppCenterError as exc: raise umcm.UMC_Error(str(exc), result=dict( display_feedback=True, title='%s %s' % (exc.title, exc.info)))
def error_handling(self, etype, exc, etraceback): ucr = ConfigRegistry() ucr.load() if isinstance(exc, OperationalError): MODULE.error(str(exc)) db_url = get_engine().url hints = [] hints.append(_('Error connecting to the Admin Diary Backend.')) hints.append(_('The database management system is "%s". Is the service running and does it respond to TCP/IP connections?') % (db_url.drivername)) if db_url.host != 'localhost': hints.append(_('Make sure your firewall allows connections to %s.') % (db_url.host)) hints.append(_('Check the password in /etc/admin-diary.secret. Is it the same on %s and on %s?') % (ucr.get('hostname'), db_url.host)) hints.append(_('Is %s allowed to connect to the database service on %s?') % (ucr.get('hostname'), db_url.host)) #hints.append(_('Did the system set up the database? If not, run /usr/share/univention-admin-diary/create-database')) raise umcm.UMC_Error('\n'.join(hints), status=500) return super(Instance, self).error_handling(exc, etype, etraceback)
def invoke_docker(self, function, app, force, values, progress): if function == 'upgrade': app = Apps().find_candidate(app) serious_problems = False progress.title = _('%s: Running tests') % (app.name,) errors, warnings = app.check(function) can_continue = force # "dry_run" if errors: MODULE.process('Cannot %s %s: %r' % (function, app.id, errors)) serious_problems = True can_continue = False if warnings: MODULE.process('Warning trying to %s %s: %r' % (function, app.id, warnings)) result = { 'serious_problems': serious_problems, 'invokation_forbidden_details': errors, 'invokation_warning_details': warnings, 'can_continue': can_continue, 'software_changes_computed': False, } if can_continue: with self.locked(): kwargs = {'noninteractive': True, 'skip_checks': ['shall_have_enough_ram', 'shall_only_be_installed_in_ad_env_with_password_service', 'must_not_have_concurrent_operation']} if function == 'install': progress.title = _('Installing %s') % (app.name,) kwargs['set_vars'] = values elif function == 'uninstall': progress.title = _('Uninstalling %s') % (app.name,) elif function == 'upgrade': progress.title = _('Upgrading %s') % (app.name,) action = get_action(function) handler = UMCProgressHandler(progress) handler.setLevel(logging.INFO) action.logger.addHandler(handler) try: result['success'] = action.call(app=app, username=self.username, password=self.password, **kwargs) except AppCenterError as exc: raise umcm.UMC_Error(str(exc), result=dict( display_feedback=True, title='%s %s' % (exc.title, exc.info))) finally: action.logger.removeHandler(handler) return result
def init(self): os.umask(0o022) # umc umask is too restrictive for app center as it creates a lot of files in docker containers self.ucr = ucr_instance() self.update_applications_done = False util.install_opener(self.ucr) self._remote_progress = {} try: self.package_manager = PackageManager( info_handler=MODULE.process, step_handler=None, error_handler=MODULE.warn, lock=False, ) except SystemError as exc: MODULE.error(str(exc)) raise umcm.UMC_Error(str(exc), status=500) self.package_manager.set_finished() # currently not working. accepting new tasks self.uu = UniventionUpdater(False) self.component_manager = util.ComponentManager(self.ucr, self.uu) get_package_manager._package_manager = self.package_manager # in order to set the correct locale for Application locale.setlocale(locale.LC_ALL, str(self.locale)) try: log_to_logfile() except IOError: pass # connect univention.appcenter.log to the progress-method handler = ProgressInfoHandler(self.package_manager) handler.setLevel(logging.INFO) get_base_logger().addHandler(handler) percentage = ProgressPercentageHandler(self.package_manager) percentage.setLevel(logging.DEBUG) get_base_logger().getChild('actions.install.progress').addHandler(percentage) get_base_logger().getChild('actions.upgrade.progress').addHandler(percentage) get_base_logger().getChild('actions.remove.progress').addHandler(percentage)
def _run_local(self, app, action, settings, auto_installed, progress): kwargs = { 'noninteractive': True, 'auto_installed': auto_installed, 'skip_checks': [ 'shall_have_enough_ram', 'shall_only_be_installed_in_ad_env_with_password_service', 'must_not_have_concurrent_operation' ], } if settings.get(app.id): kwargs['set_vars'] = settings[app.id] if action == 'install': progress.title = _('Installing %s') % (app.name, ) elif action == 'remove': progress.title = _('Uninstalling %s') % (app.name, ) elif action == 'upgrade': progress.title = _('Upgrading %s') % (app.name, ) action = get_action(action) handler = UMCProgressHandler(progress) handler.setLevel(logging.INFO) action.logger.addHandler(handler) try: package_manager = get_package_manager() with package_manager.no_umc_restart(exclude_apache=True): success = action.call(app=[app], username=self.username, password=self.password, **kwargs) return {'success': success} except AppCenterError as exc: raise umcm.UMC_Error(str(exc), result=dict(display_feedback=True, title='%s %s' % (exc.title, exc.info))) finally: action.logger.removeHandler(handler)
def locked(self): try: with self.package_manager.locked(reset_status=True, set_finished=True): yield except LockError: raise umcm.UMC_Error(_('Another package operation is in progress'))
def invoke(self, request): # ATTENTION!!!!!!! # this function has to stay compatible with the very first App Center installations (Dec 2012) # if you add new arguments that change the behaviour # you should add a new method (see invoke_dry_run) or add a function name (e.g. install-schema) # this is necessary because newer app center may talk remotely with older one # that does not understand new arguments and behaves the old way (in case of # dry_run: install application although they were asked to dry_run) host = request.options.get('host') function = request.options.get('function') send_as = function if function.startswith('install'): function = 'install' if function.startswith('update'): function = 'update' application_id = request.options.get('application') Application.all(only_local=True) # if not yet cached, cache. but use only local inis application = Application.find(application_id) if application is None: raise umcm.UMC_Error(_('Could not find an application for %s') % (application_id,)) force = request.options.get('force') only_dry_run = request.options.get('only_dry_run') dont_remote_install = request.options.get('dont_remote_install') only_master_packages = send_as.endswith('schema') MODULE.process('Try to %s (%s) %s on %s. Force? %r. Only master packages? %r. Prevent installation on other systems? %r. Only dry run? %r.' % (function, send_as, application_id, host, force, only_master_packages, dont_remote_install, only_dry_run)) # REMOTE invocation! if host and host != self.ucr.get('hostname'): try: client = Client(host, self.username, self.password) result = client.umc_command('appcenter/invoke', request.options).result except (ConnectionError, HTTPError) as exc: MODULE.error('Error during remote appcenter/invoke: %s' % (exc,)) result = { 'unreachable': [host], 'master_unreachable': True, 'serious_problems': True, 'software_changes_computed': True, # not really... } else: if result['can_continue']: def _thread_remote(_client, _package_manager): with _package_manager.locked(reset_status=True, set_finished=True): _package_manager.unlock() # not really locked locally, but busy, so "with locked()" is appropriate Application._query_remote_progress(_client, _package_manager) def _finished_remote(thread, result): if isinstance(result, BaseException): MODULE.warn('Exception during %s %s: %s' % (function, application_id, str(result))) thread = notifier.threads.Simple('invoke', notifier.Callback(_thread_remote, client, self.package_manager), _finished_remote) thread.run() self.finished(request.id, result) return # make sure that the application can be installed/updated can_continue = True delayed_can_continue = True serious_problems = False result = { 'install': [], 'remove': [], 'broken': [], 'unreachable': [], 'master_unreachable': False, 'serious_problems': False, 'hosts_info': {}, 'problems_with_hosts': False, 'serious_problems_with_hosts': False, 'invokation_forbidden_details': {}, 'invokation_warning_details': {}, 'software_changes_computed': False, } if not application: MODULE.process('Application not found: %s' % application_id) can_continue = False if can_continue and not only_master_packages: forbidden, warnings = application.check_invokation(function, self.package_manager) if forbidden: MODULE.process('Cannot %s %s: %r' % (function, application_id, forbidden)) result['invokation_forbidden_details'] = forbidden can_continue = False serious_problems = True if warnings: MODULE.process('Warning trying to %s %s: %r' % (function, application_id, forbidden)) result['invokation_warning_details'] = warnings if not force: # dont stop "immediately". # compute the package changes! delayed_can_continue = False result['serious_problems'] = serious_problems result['can_continue'] = can_continue try: if can_continue: if self._working(): # make it multi-tab safe (same session many buttons to be clicked) raise LockError() with self.package_manager.locked(reset_status=True): previously_registered_by_dry_run = False if can_continue and function in ('install', 'update'): remove_component = only_dry_run dry_run_result, previously_registered_by_dry_run = application.install_dry_run(self.package_manager, self.component_manager, remove_component=remove_component, username=self._username, password=self.password, only_master_packages=only_master_packages, dont_remote_install=dont_remote_install, function=function, force=force) result.update(dry_run_result) result['software_changes_computed'] = True serious_problems = bool(result['broken'] or result['master_unreachable'] or result['serious_problems_with_hosts']) if serious_problems or (not force and (result['unreachable'] or result['install'] or result['remove'] or result['problems_with_hosts'])): MODULE.process('Problems encountered or confirmation required. Removing component %s' % application.component_id) if not remove_component: # component was not removed automatically after dry_run if application.candidate: # operation on candidate failed. re-register original application application.register(self.component_manager, self.package_manager) else: # operation on self failed. unregister all application.unregister_all_and_register(None, self.component_manager, self.package_manager) can_continue = False elif can_continue and function in ('uninstall',) and not force: result['remove'] = application.uninstall_dry_run(self.package_manager) result['software_changes_computed'] = True can_continue = False can_continue = can_continue and delayed_can_continue and not only_dry_run result['serious_problems'] = serious_problems result['can_continue'] = can_continue if can_continue and not only_dry_run: def _thread(module, application, function): with module.package_manager.locked(set_finished=True): with module.package_manager.no_umc_restart(exclude_apache=True): if function in ('install', 'update'): # dont have to add component: already added during dry_run return application.install(module.package_manager, module.component_manager, add_component=only_master_packages, send_as=send_as, username=self._username, password=self.password, only_master_packages=only_master_packages, dont_remote_install=dont_remote_install, previously_registered_by_dry_run=previously_registered_by_dry_run) else: return application.uninstall(module.package_manager, module.component_manager, self._username, self.password) def _finished(thread, result): if isinstance(result, BaseException): MODULE.warn('Exception during %s %s: %s' % (function, application_id, str(result))) thread = notifier.threads.Simple('invoke', notifier.Callback(_thread, self, application, function), _finished) thread.run() else: self.package_manager.set_finished() # nothing to do, ready to take new commands self.finished(request.id, result) except LockError: # make it thread safe: another process started a package manager # this module instance already has a running package manager raise umcm.UMC_Error(_('Another package operation is in progress'))
def invoke(self, request): # ATTENTION!!!!!!! # this function has to stay compatible with the very first App Center installations (Dec 2012) # if you add new arguments that change the behavior # you should add a new method (see invoke_dry_run) or add a function name (e.g. install-schema) # this is necessary because newer app center may talk remotely with older one # that does not understand new arguments and behaves the old way (in case of # dry_run: install application although they were asked to dry_run) host = request.options.get('host') function = request.options.get('function') send_as = function if function.startswith('install'): function = 'install' if function.startswith('update'): function = 'upgrade' if function == 'uninstall': function = 'remove' app_id = request.options.get('application') app = Apps().find(app_id) if app is None: raise umcm.UMC_Error(_('Could not find an application for %s') % (app_id,)) force = request.options.get('force') values = request.options.get('values') only_dry_run = request.options.get('only_dry_run') dont_remote_install = request.options.get('dont_remote_install') only_master_packages = send_as.endswith('schema') MODULE.process('Try to %s (%s) %s on %s. Force? %r. Only master packages? %r. Prevent installation on other systems? %r. Only dry run? %r.' % (function, send_as, app_id, host, force, only_master_packages, dont_remote_install, only_dry_run)) # REMOTE invocation! if host and host != self.ucr.get('hostname'): try: client = Client(host, self.username, self.password) result = client.umc_command('appcenter/invoke', request.options).result except (ConnectionError, HTTPError) as exc: MODULE.error('Error during remote appcenter/invoke: %s' % (exc,)) result = { 'unreachable': [host], 'master_unreachable': True, 'serious_problems': True, 'software_changes_computed': True, # not really... } else: if result['can_continue']: def _thread_remote(_client): with self.is_working(): self._query_remote_progress(_client) def _finished_remote(thread, result): if isinstance(result, BaseException): MODULE.warn('Exception during %s %s: %s' % (function, app_id, str(result))) thread = notifier.threads.Simple('invoke', notifier.Callback(_thread_remote, client), _finished_remote) thread.run() self.finished(request.id, result) return # make sure that the application can be installed/updated action = get_action(function)() args = action._build_namespace(app=app, username=self.username, password=self.password, noninteractive=True, skip_checks=['shall_have_enough_ram', 'shall_only_be_installed_in_ad_env_with_password_service', 'must_not_have_concurrent_operation'], send_info=not only_master_packages, set_vars=values, dry_run=True, install_master_packages_remotely=False, only_master_packages=only_master_packages) can_continue = True delayed_can_continue = True serious_problems = False result = { 'install': [], 'remove': [], 'broken': [], 'unreachable': [], 'master_unreachable': False, 'serious_problems': False, 'hosts_info': {}, 'problems_with_hosts': False, 'serious_problems_with_hosts': False, 'invokation_forbidden_details': {}, 'invokation_warning_details': {}, 'software_changes_computed': False, } if not app: MODULE.process('Application not found: %s' % app_id) can_continue = False if can_continue and not only_master_packages: if function == 'upgrade': app = Apps().find_candidate(app) if app is None: forbidden, warnings = {'must_have_candidate': False}, {} else: forbidden, warnings = app.check(function) if forbidden: MODULE.process('Cannot %s %s: %r' % (function, app_id, forbidden)) result['invokation_forbidden_details'] = forbidden can_continue = False serious_problems = True if warnings: MODULE.process('Warning trying to %s %s: %r' % (function, app_id, forbidden)) result['invokation_warning_details'] = warnings if not force: # don't stop "immediately". # compute the package changes! delayed_can_continue = False result['serious_problems'] = serious_problems result['can_continue'] = can_continue if can_continue: with self.locked(): if can_continue and function in ('install', 'upgrade'): result.update(self._install_dry_run_remote(app, function, dont_remote_install, force)) serious_problems = bool(result['master_unreachable'] or result['serious_problems_with_hosts']) if serious_problems: args.dry_run = True result.update(action.dry_run(app, args)) result['software_changes_computed'] = True serious_problems = bool(result['broken'] or serious_problems) if serious_problems or (not force and (result['unreachable'] or result['install'] or result['remove'] or result['problems_with_hosts'])): can_continue = False elif can_continue and function in ('remove',) and not force: result.update(action.dry_run(app, args)) result['software_changes_computed'] = True can_continue = False can_continue = can_continue and delayed_can_continue and not only_dry_run result['serious_problems'] = serious_problems result['can_continue'] = can_continue if can_continue and not only_dry_run: def _thread(module, app, function): with module.is_working(): if not dont_remote_install and function != 'remove': self._install_master_packages_on_hosts(app, function) with module.package_manager.no_umc_restart(exclude_apache=True): try: args.dry_run = False args.install_master_packages_remotely = False return action.call_with_namespace(args) except AppCenterError as exc: raise umcm.UMC_Error(str(exc), result=dict( display_feedback=True, title='%s %s' % (exc.title, exc.info))) def _finished(thread, result): if isinstance(result, BaseException): MODULE.warn('Exception during %s %s: %s' % (function, app_id, str(result))) thread = notifier.threads.Simple('invoke', notifier.Callback(_thread, self, app, function), _finished) thread.run() self.finished(request.id, result)
def get(self, application): domain = get_action('domain') app = Apps().find(application) if app is None: raise umcm.UMC_Error(_('Could not find an application for %s') % (application,)) return domain.to_dict([app])[0]