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
Esempio n. 2
0
	def _install_master_packages_on_host(self, app, function, host):
		client = Client(host, self.username, self.password)
		result = client.umc_command('appcenter/invoke', {'function': function, 'application': app.id, 'force': True, 'dont_remote_install': True}).result
		if result['can_continue']:
			all_errors = self._query_remote_progress(client)
			return len(all_errors) == 0
		else:
			MODULE.warn('%r' % result)
			return False
Esempio n. 3
0
			def _check_remote_host(app_id, host, host_is_master, username, password, force, remote_function):
				MODULE.process('Starting dry_run for %s on %s' % (app_id, host))
				MODULE.process('%s: Connecting...' % host)
				try:
					client = Client(host, username, password)
				except (ConnectionError, HTTPError) as exc:
					MODULE.warn('_check_remote_host: %s: %s' % (host, exc))
					unreachable.append(host)
					if host_is_master:
						remote_info['master_unreachable'] = True
				else:
					MODULE.process('%s: ... done' % host)
					host_info = {}
					MODULE.process('%s: Getting version...' % host)
					try:
						host_version = client.umc_command('appcenter/version', {'version': info.get_compatibility()}).result
					except Forbidden:
						# command is not yet known (older app center)
						MODULE.process('%s: ... forbidden!' % host)
						host_version = None
					except (ConnectionError, HTTPError) as exc:
						MODULE.warn('%s: Could not get appcenter/version: %s' % (exc,))
						raise
					except Exception as exc:
						MODULE.error('%s: Exception: %s' % (host, exc))
						raise
					MODULE.process('%s: ... done' % host)
					host_info['compatible_version'] = info.is_compatible(host_version)
					MODULE.process('%s: Invoking %s ...' % (host, remote_function))
					try:
						host_info['result'] = client.umc_command('appcenter/invoke_dry_run', {
							'function': remote_function,
							'application': app_id,
							'force': force,
							'dont_remote_install': True,
						}).result
					except Forbidden:
						# command is not yet known (older app center)
						MODULE.process('%s: ... forbidden!' % host)
						host_info['result'] = {'can_continue': False, 'serious_problems': False}
					except (ConnectionError, HTTPError) as exc:
						MODULE.warn('Could not get appcenter/version: %s' % (exc,))
						raise
					MODULE.process('%s: ... done' % host)
					if not host_info['compatible_version'] or not host_info['result']['can_continue']:
						remote_info['problems_with_hosts'] = True
						if host_info['result']['serious_problems'] or not host_info['compatible_version']:
							remote_info['serious_problems_with_hosts'] = True
					hosts_info[host] = host_info
				MODULE.process('Finished dry_run for %s on %s' % (app_id, host))
def join_ad():
	""" Function for joining an AD domain, mimicking a join from umc"""

	global client
	client = Client(options.host, options.username, options.password, language='en-US')

	if options.sync_mode:
		# join in sync mode:
		print '=== AD-JOIN SYNC MODE SELECTED ==='
		join_sync_mode()
	else:
		# join in read mode:
		print '=== AD-JOIN READ MODE SELECTED ==='
		join_read_mode()
Esempio n. 5
0
	def _decorator(self, request, *args, **kwargs):
		if not IS_SELFSERVICE_MASTER:
			try:
				language = str(self.locale).split('.')[0].replace('_', '-')
				client = Client(SELFSERVICE_MASTER, language=language)
				client.authenticate_with_machine_account()
				response = client.umc_command(request.arguments[0], request.options)
			except (Unauthorized, ConnectionError) as exc:
				raise UMC_Error(_('The connection to the server could not be established. Please try again later. Error message was: %s') % (exc,), status=503)
			except HTTPError as exc:
				response = exc.response
			self.finished(request.id, response.result, message=response.message, status=response.status)
			return
		return func(self, request, *args, **kwargs)
Esempio n. 6
0
        try:
            result = client.umc_command(path).result
        except univention.lib.umc.ConnectionError:
            print('... Apache down? Ignoring...')
            continue
        print(result)
        if result.get('finished', False):
            break
    else:
        raise Exception("wait timeout")
    print(result)
    assert not result['errors']


client = Client(options.host,
                options.username,
                options.password,
                language='en-US')
request_options = {
    "ip": options.domain_host,
    "username": options.domain_admin,
    "password": options.domain_password
}

print('starting connect')
response = client.umc_command("adtakeover/connect", request_options)
print(response.result)
assert response.status == 200

try:
    print('starting copy')
    response = client.umc_command("adtakeover/run/copy", request_options)
	def __init__(self, host, username=None, password=None, error_handler=None):
		# type: (str, Optional[str], Optional[str], Optional[Callable[[str], None]]) -> None
		self.client = Client(host, username, password)
		self._error_handler = error_handler
		self.build_data = self.client._Client__build_data
Esempio n. 8
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)
Esempio n. 9
0
	def invoke_remote_docker(self, host, function, app, force, values, progress):
		options = {'function': function, 'app': app, 'force': force, 'values': values}
		client = Client(host, self.username, self.password)
		result = client.umc_command('appcenter/docker/invoke', options).result
		self._remote_progress[progress.id] = client, result['id']
 def __init__(self, host, username=None, password=None, error_handler=None):
     self.client = Client(host, username, password)
     self._error_handler = error_handler
     self.build_data = self.client._Client__build_data
Esempio n. 11
0
def umc(username, password, master, path, options=None, flavor=None):
	MODULE.info('Executing on %r as %r: %r flavor=%r options=%r' % (master, username, path, flavor, options))
	client = Client(master, username, password)
	return client.umc_command(path, options, flavor)
Esempio n. 12
0
        def _thread():
            # perform all actions inside a thread...
            # collect files
            progress.component(_('Collecting exam files...'))
            if project:
                project.collect()
            progress.add_steps(10)

            # open a new connection to the master UMC
            master = ucr['ldap/master']
            try:
                client = Client(master)
                client.authenticate_with_machine_account()
            except (ConnectionError, HTTPError) as exc:
                MODULE.error('Could not connect to UMC on %s: %s' %
                             (master, exc))
                raise UMC_Error(
                    _('Could not connect to master server %s.') % (master, ))

            school = SchoolSearchBase.getOU(request.options['room'])

            # unset exam mode for the given computer room
            progress.component(_('Configuring the computer room...'))
            client.umc_command(
                'schoolexam-master/unset-computerroom-exammode',
                dict(
                    roomdn=request.options['room'],
                    school=school,
                )).result
            progress.add_steps(5)

            # delete exam users accounts
            if project:
                # get a list of user accounts in parallel exams
                parallelUsers = dict([
                    (iuser.username, iproject.description)
                    for iproject in util.distribution.Project.list()
                    if iproject.name != project.name
                    for iuser in iproject.recipients
                ])

                progress.component(_('Removing exam accounts'))
                percentPerUser = 25.0 / (1 + len(project.recipients))
                for iuser in project.recipients:
                    progress.info(
                        '%s, %s (%s)' %
                        (iuser.lastname, iuser.firstname, iuser.username))
                    try:
                        if iuser.username not in parallelUsers:
                            # remove first the home directory
                            shutil.rmtree(iuser.unixhome, ignore_errors=True)

                            # remove LDAP user entry
                            client.umc_command(
                                'schoolexam-master/remove-exam-user',
                                dict(
                                    userdn=iuser.dn,
                                    school=school,
                                )).result
                            MODULE.info('Exam user has been removed: %s' %
                                        iuser.dn)
                        else:
                            MODULE.process(
                                'Cannot remove the user account %s as it is registered for the running exam "%s", as well'
                                % (iuser.dn, parallelUsers[iuser.username]))
                    except (ConnectionError, HTTPError) as e:
                        MODULE.warn(
                            'Could not remove exam user account %s: %s' %
                            (iuser.dn, e))

                    # indicate the user has been processed
                    progress.add_steps(percentPerUser)

                progress.add_steps(percentPerUser)
Esempio n. 13
0
        def _thread():
            # make sure that a project with the same name does not exist
            directory = request.options['directory']
            # get absolute path of project file and test for existance
            fn_test_project = util.distribution.Project.sanitize_project_filename(
                directory)
            if os.path.exists(fn_test_project):
                raise UMC_Error(
                    _('An exam with the name "%s" already exists. Please choose a different name for the exam.'
                      ) % (directory, ))

            # validate the project data and save project
            my.project = util.distribution.Project(
                dict(
                    name=directory,
                    description=request.options['name'],
                    files=request.options.get('files'),
                    sender=sender,
                ))
            my.project.validate()
            my.project.save()

            # copy files into project directory
            if self._tmpDir:
                for ifile in my.project.files:
                    isrc = os.path.join(self._tmpDir, ifile)
                    itarget = os.path.join(my.project.cachedir, ifile)
                    if os.path.exists(isrc):
                        # copy file to cachedir
                        shutil.move(isrc, itarget)
                        os.chown(itarget, 0, 0)

            # open a new connection to the master UMC
            try:
                master = ucr['ldap/master']
                client = Client(master)
                client.authenticate_with_machine_account()
            except (ConnectionError, HTTPError) as exc:
                MODULE.error('Could not connect to UMC on %s: %s' %
                             (master, exc))
                raise UMC_Error(
                    _('Could not connect to master server %s.') %
                    ucr.get('ldap/master'))

            # mark the computer room for exam mode
            progress.component(
                _('Preparing the computer room for exam mode...'))
            client.umc_command(
                'schoolexam-master/set-computerroom-exammode',
                dict(
                    school=request.options['school'],
                    roomdn=request.options['room'],
                )).result  # FIXME: no error handling
            progress.add_steps(5)

            # read all recipients and fetch all user objects
            users = []
            for idn in request.options['recipients']:
                ientry = util.distribution.openRecipients(idn, ldap_user_read)
                if not ientry:
                    continue
                # recipients can in theory be users or groups
                members = []
                if isinstance(ientry, util.distribution.User):
                    members = [ientry]
                elif isinstance(ientry, util.distribution.Group):
                    members = ientry.members
                for entry in members:
                    # ignore exam users
                    user = User.from_dn(entry.dn, None, ldap_user_read)
                    if not user.is_exam_student(ldap_user_read):
                        users.append(entry)

            # start to create exam user accounts
            progress.component(_('Preparing exam accounts'))
            percentPerUser = 25.0 / (1 + len(users))
            examUsers = set()
            student_dns = set()
            usersReplicated = set()
            for iuser in users:
                progress.info(
                    '%s, %s (%s)' %
                    (iuser.lastname, iuser.firstname, iuser.username))
                try:
                    ires = client.umc_command(
                        'schoolexam-master/create-exam-user',
                        dict(
                            school=request.options['school'],
                            userdn=iuser.dn,
                        )).result
                    examuser_dn = ires.get('examuserdn')
                    examUsers.add(examuser_dn)
                    student_dns.add(iuser.dn)
                    MODULE.info('Exam user has been created: %r' % examuser_dn)
                except (ConnectionError, HTTPError) as exc:
                    MODULE.warn(
                        'Could not create exam user account for %r: %s' %
                        (iuser.dn, exc))

                # indicate the the user has been processed
                progress.add_steps(percentPerUser)

            client.umc_command(
                'schoolexam-master/add-exam-users-to-groups',
                dict(
                    users=list(student_dns),
                    school=request.options['school'],
                ))

            progress.add_steps(percentPerUser)

            # wait for the replication of all users to be finished
            progress.component(_('Preparing user home directories'))
            recipients = []  # list of User objects for all exam users
            openAttempts = 30 * 60  # wait max. 30 minutes for replication
            while (len(examUsers) > len(usersReplicated)) and (openAttempts >
                                                               0):
                openAttempts -= 1
                MODULE.info(
                    'waiting for replication to be finished, %s user objects missing'
                    % (len(examUsers) - len(usersReplicated)))
                for idn in examUsers - usersReplicated:
                    try:
                        ldap_user_read.get(idn, required=True)
                    except ldap.NO_SUCH_OBJECT:
                        continue  # not replicated yet
                    iuser = util.distribution.openRecipients(
                        idn, ldap_user_read)
                    if not iuser:
                        continue  # not a users/user object
                    MODULE.info('user has been replicated: %s' % idn)

                    # call hook scripts
                    if 0 != subprocess.call([
                            '/bin/run-parts', CREATE_USER_POST_HOOK_DIR,
                            '--arg', iuser.username, '--arg', iuser.dn,
                            '--arg', iuser.homedir
                    ]):
                        raise ValueError(
                            'failed to run hook scripts for user %r' %
                            (iuser.username))

                    # store User object in list of final recipients
                    recipients.append(iuser)

                    # mark the user as replicated
                    usersReplicated.add(idn)
                    progress.info(
                        '%s, %s (%s)' %
                        (iuser.lastname, iuser.firstname, iuser.username))
                    progress.add_steps(percentPerUser)

                # wait a second
                time.sleep(1)

            progress.add_steps(percentPerUser)

            if openAttempts <= 0:
                MODULE.error(
                    'replication timeout - %s user objects missing: %r ' %
                    ((len(examUsers) - len(usersReplicated)),
                     (examUsers - usersReplicated)))
                raise UMC_Error(
                    _('Replication timeout: could not create all exam users'))

            # update the final list of recipients
            my.project.recipients = recipients
            my.project.save()

            # update local NSS group cache
            if ucr.is_true('nss/group/cachefile', True):
                cmd = ['/usr/lib/univention-pam/ldap-group-to-file.py']
                if ucr.is_true('nss/group/cachefile/check_member', False):
                    cmd.append('--check_member')
                MODULE.info('Updating local nss group cache...')
                if subprocess.call(cmd):
                    MODULE.error('Updating local nss group cache failed: %s' %
                                 ' '.join(cmd))
                else:
                    MODULE.info(
                        'Update of local nss group cache finished successfully.'
                    )

            # distribute exam files
            progress.component(_('Distributing exam files'))
            progress.info('')
            my.project.distribute()
            progress.add_steps(20)

            # prepare room settings via UMCP...
            #   first step: acquire room
            #   second step: adjust room settings
            progress.component(_('Prepare room settings'))
            try:
                user_client = Client(None, self.username, self.password)
            except (ConnectionError, HTTPError) as exc:
                MODULE.warn('Authentication failed: %s' % (exc, ))
                raise UMC_Error(_('Could not connect to local UMC server.'))

            room = request.options['room']
            MODULE.info('Acquire room: %s' % (room, ))
            user_client.umc_command('computerroom/room/acquire',
                                    dict(
                                        room=request.options['room'], )).result
            progress.add_steps(1)
            MODULE.info('Adjust room settings:\n%s' % '\n'.join(
                ['  %s=%s' % (k, v) for k, v in request.options.iteritems()]))
            user_client.umc_command(
                'computerroom/exam/start',
                dict(
                    room=room,
                    examDescription=request.options['name'],
                    exam=directory,
                    examEndTime=request.options.get('examEndTime'),
                )).result
            progress.add_steps(4)
            user_client.umc_command(
                'computerroom/settings/set',
                dict(
                    room=room,
                    internetRule=request.options['internetRule'],
                    customRule=request.options.get('customRule'),
                    shareMode=request.options['shareMode'],
                    printMode='default',
                )).result
            progress.add_steps(5)
Esempio n. 14
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'))