示例#1
0
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.'))
示例#4
0
	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
示例#6
0
	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
示例#11
0
	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)
示例#13
0
	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
示例#14
0
	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]
示例#15
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
示例#16
0
					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)
示例#18
0
	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
示例#19
0
	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)
示例#21
0
	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'))
示例#22
0
	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'))
示例#23
0
	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)
示例#24
0
	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]