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 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 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)