コード例 #1
0
ファイル: app_center.py プロジェクト: B-Rich/smart
	def _fetch_file(self, key, url):
		try:
			# open the license file 
			fp = util.urlopen(url)
			self._options[key] = ''.join(fp.readlines()).strip()
		except (urllib2.HTTPError, urllib2.URLError) as e:
			MODULE.warn('No information for %s available (%s): %s' % (key, e, url))
コード例 #2
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _thread( request ):
			result = []
			for ldap_dn in request.options:
				if request.flavor == 'users/self':
					ldap_dn = self._user_dn
				module = get_module( request.flavor, ldap_dn )
				if module is None:
					MODULE.process( 'A module for the LDAP DN %s could not be found' % ldap_dn )
					continue
				obj = module.get( ldap_dn )
				if obj:
					props = obj.info
					for passwd in module.password_properties:
						if passwd in props:
							del props[ passwd ]
					props[ '$dn$' ] = obj.dn
					props[ '$options$' ] = {}
					for opt in module.get_options( udm_object = obj ):
						props[ '$options$' ][ opt[ 'id' ] ] = opt[ 'value' ]
					props[ '$policies$' ] = {}
					for policy in obj.policies:
						pol_mod = get_module( None, policy )
						if pol_mod and pol_mod.name:
							props[ '$policies$' ][ pol_mod.name ] = policy
					props[ '$labelObjectType$' ] = module.title;
					result.append( props )
				else:
					MODULE.process( 'The LDAP object for the LDAP DN %s could not be found' % ldap_dn )
			return result
コード例 #3
0
ファイル: __init__.py プロジェクト: decoit/asterisk4ucs
def getUserAndMailbox(userdn):
	co, lo, pos = getCoLoPos()

	server = univention.admin.modules.get("asterisk/server")
	univention.admin.modules.init(lo, pos, server)
	objs = server.lookup(co, lo, None)

	checkServers = []
	for obj in objs:
			checkServers.append({
				"label": obj["commonName"],
			})

	MODULE.error('User: server: %s' % len(checkServers))
	if len(checkServers) >0 :
		co, lo = getCoLo()

		user = getUser(co, lo, userdn)

		mailbox = user.get("mailbox")
		if mailbox:
			mailbox = getMailbox(co, lo, mailbox)

		return user, mailbox
	elif len(checkServers) == 0 :
		MODULE.error('Fehler gefunden!')
		mailbox = "KeinServer"
		user = "******"
		return user, mailbox
コード例 #4
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def list_jobs(self,request):
		""" returns list of jobs for one printer. """

		# ----------- DEBUG -----------------
		MODULE.info("printers/jobs/query invoked with:")
		pp = pprint.PrettyPrinter(indent=4)
		st = pp.pformat(request.options).split("\n")
		for s in st:
			MODULE.info("   << %s" % s)
		# -----------------------------------

		printer = request.options.get('printer','')
		result = self._job_list(printer)

		# ---------- DEBUG --------------
		MODULE.info("printers/jobs/query returns:")
		pp = pprint.PrettyPrinter(indent=4)
		st = ''
		if len(result) > 5:
			tmp = result[0:5]
			MODULE.info("   >> %d entries, first 5 are:" % len(result))
			st = pp.pformat(tmp).split("\n")
		else:
			st = pp.pformat(result).split("\n")
		for s in st:
			MODULE.info("   >> %s" % s)
		# --------------------------------

		self.finished(request.id,result)
コード例 #5
0
ファイル: partition.py プロジェクト: kielfriedt/smart
 def partitions_info(self, request):
     result = {}
     message = None
     try:
         fs = fstab.File()
         mt = mtab.File()
     except IOError as error:
         MODULE.error("Could not open %s" % error.filename)
         message = _("Could not open %s") % error.filename
         request.status = MODULE_ERR
     else:
         partition = fs.find(spec=request.options["partitionDevice"])
         if partition:
             mounted_partition = mt.get(partition.spec)
             if mounted_partition:
                 result["mountPoint"] = mounted_partition.mount_point
                 result["filesystem"] = mounted_partition.type
                 result["options"] = mounted_partition.options
                 request.status = SUCCESS
             else:
                 request.status = MODULE_ERR
                 message = _("This partition is currently not mounted")
         else:
             request.status = MODULE_ERR
             message = _("No partition found")
     self.finished(request.id, result, message)
コード例 #6
0
ファイル: partition.py プロジェクト: kielfriedt/smart
 def partitions_query(self, request):
     result = []
     message = None
     try:
         fs = fstab.File()
         mt = mtab.File()
     except IOError as error:
         MODULE.error("Could not open %s" % error.filename)
         message = _("Could not open %s") % error.filename
         request.status = MODULE_ERR
     else:
         partitions = fs.get(["xfs", "ext3", "ext2"], False)  # TODO: ext4?
         for partition in partitions:
             list_entry = {}
             list_entry["partitionDevice"] = partition.spec
             list_entry["mountPoint"] = partition.mount_point
             list_entry["partitionSize"] = None
             list_entry["freeSpace"] = None
             list_entry["inUse"] = None
             mounted_partition = mt.get(partition.spec)
             if mounted_partition:
                 partition_info = df.DeviceInfo(partition.mount_point)
                 list_entry["partitionSize"] = tools.block2byte(partition_info.size(), "GB", 1)
                 list_entry["freeSpace"] = tools.block2byte(partition_info.free(), "GB", 1)
                 if "usrquota" in mounted_partition.options:
                     list_entry["inUse"] = True
                 else:
                     list_entry["inUse"] = False
             result.append(list_entry)
         request.status = SUCCESS
     self.finished(request.id, result, message)
コード例 #7
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def save( self, request ):
		"""Saves the UCS Active Directory Connector configuration

		options:
			LDAP_Host: hostname of the AD server
			LDAP_Base: LDAP base of the AD server
			LDAP_BindDN: LDAP DN to use for authentication
			KerberosDomain: kerberos domain
			PollSleep: time in seconds between polls
			RetryRejected: how many time to retry a synchronisation
			MappingSyncMode: synchronisation mode
			MappingGroupLanguage: language of the AD server

		return: { 'success' : (True|False), 'message' : <details> }
		"""

		self.required_options( request, *map( lambda x: x[ 0 ], Instance.OPTION_MAPPING ) )
		self.guessed_baseDN = None

		try:
			fn = '%s/.htaccess' % DIR_WEB_AD
			fd = open( fn, 'w' )
			fd.write( 'require user %s\n' % self._username )
			fd.close()
			os.chmod( fn, 0644 )
			os.chown( fn, 0, 0 )
		except Exception, e:
			message = _( 'An error occured while saving .htaccess (filename=%(fn)s ; exception=%(exception)s)') % { 'fn': fn, 'exception': e.__class__.__name__ }
			MODULE.process( 'An error occured while saving .htaccess (filename=%(fn)s ; exception=%(exception)s)' % { 'fn': fn, 'exception': e.__class__.__name__ } )
			self.finished( request.id, { 'success' : False, 'message' : message } )
			return
コード例 #8
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _thread(request, obj, username, password):
			# acquire the lock until the scripts have been executed
			self._finishedResult = False
			obj._finishedLock.acquire()
			try:
				self._progressParser.reset()

				# write the profile file and run setup scripts
				util.pre_save(values, orgValues)

				# on unjoined DC master the nameserver must be set to the external nameserver
				if newrole == 'domaincontroller_master' and not orgValues.get('joined'):
					for i in range(1,4):
						# overwrite these values only if they are set, because the UMC module
						# will save only changed values
						if values.get( 'dns/forwarder%d'%i ):
							values[ 'nameserver%d'%i ] = values.get( 'dns/forwarder%d'%i )

				MODULE.info('saving profile values')
				util.write_profile(values)

				# unjoined DC master (that is not being converted to a basesystem) -> run the join script
				MODULE.info('runnning system setup join script')
				util.run_joinscript( self._progressParser, username, password )

				# done :)
				self._finishedResult = True

				# we should do a cleanup now
				self._cleanup_required = True

				return True
			finally:
				obj._finishedLock.release()
コード例 #9
0
ファイル: uvmmd.py プロジェクト: B-Rich/smart
	def request( self, command, **kwargs ):
		MODULE.info( 'Sending request %s to UVMM daemon ...' % command )
		try:
			request = eval( 'protocol.Request_%s()' % command )
		except NameError, AttributeError:
			MODULE.error( 'Failed to create request %s' % command )
			raise UVMM_Error( _( 'The given UVMM command is not known' ) )
コード例 #10
0
ファイル: user.py プロジェクト: B-Rich/smart
		def _thread(request):
			message = None
			success = True
			result = []

			partition = request.options['partitionDevice']
			unicode_user = request.options['user']
			user = unicode_user.encode('utf-8')
			size_soft = request.options['sizeLimitSoft']
			size_hard = request.options['sizeLimitHard']
			file_soft = request.options['fileLimitSoft']
			file_hard = request.options['fileLimitHard']
			self._check_error(request, partition)
			failed = tools.setquota(partition, user, tools.byte2block(size_soft),
			                        tools.byte2block(size_hard),
			                        file_soft, file_hard)
			if failed:
				MODULE.error('Failed to modify quota settings for user %s '
				             'on partition %s' % (user, partition))
				message = _('Failed to modify quota settings for user %s on '
				            'partition %s') % (user, partition)
				request.status = MODULE_ERR
				self.finished(request.id, None, message)
			message = _('Successfully set quota settings')
			return {'result': result, 'message': message, 'success': success}
コード例 #11
0
ファイル: app_center.py プロジェクト: B-Rich/smart
	def install(self, package_manager, component_manager, add_component=True):
		try:
			# remove all existing component versions
			for iapp in self.versions:
				# dont remove yourself (if already added)
				if iapp is not self:
					component_manager.remove_app(iapp)

			# add the new repository component for the app
			ucr.load()
			is_master = ucr.get('server/role') in ('domaincontroller_master', 'domaincontroller_backup')  # packages need to be installed on backup AND master systems
			to_install = self.get('defaultpackages')
			if is_master and self.get('defaultpackagesmaster'):
				to_install.extend(self.get('defaultpackagesmaster'))

			if add_component:
				component_manager.put_app(self)
				package_manager.update()

			# install + dist_upgrade
			package_manager.log('\n== INSTALLING %s AT %s ==\n' % (self.name, datetime.now()))
			package_manager.commit(install=to_install, dist_upgrade=True)

			# successful installation
			status = 200
		except:
			MODULE.warn(traceback.format_exc())
			status = 500
		self._send_information('install', status)
		return status == 200
コード例 #12
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def colors( self, request ):
		"""Returns a list of all existing colors."""
		MODULE.info( 'MODULEID.colors: options: %s' % str( request.options ) )
		allColors = set(map(lambda x: x['color'], Instance.entries))
		allColors = map(lambda x: { 'id': x, 'label': x }, allColors)
		allColors.append({ 'id': 'None', 'label': _('All colors') })
		MODULE.info( 'MODULEID.colors: result: %s' % str( allColors ) )
		self.finished(request.id, allColors)
コード例 #13
0
ファイル: __init__.py プロジェクト: decoit/asterisk4ucs
def getServer(dn):
	co, lo, pos = getCoLoPos()
	server = univention.admin.modules.get("asterisk/server")
	univention.admin.modules.init(lo, pos, server)
	obj = server.object(co, lo, None, dn)
	MODULE.error("server dn: %s" % dn)
	obj.open()

	return obj
コード例 #14
0
ファイル: app_center.py プロジェクト: B-Rich/smart
	def uninstall_dry_run(self, package_manager):
		MODULE.info('Invoke uninstall_dry_run')
		package_manager.reopen_cache()
		to_uninstall = package_manager.get_packages(self.get('defaultpackages'))
		for package in to_uninstall:
			package.mark_delete()
		packages = [pkg.name for pkg in package_manager.packages() if pkg.is_auto_removable]
		package_manager.reopen_cache()
		return packages
コード例 #15
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _send_return( thread, result, request ):
			import traceback

			if not isinstance( result, BaseException ):
				MODULE.info( 'sending mail: completed successfully' )
				self.finished( request.id, True )
			else:
				msg = '%s\n%s: %s\n' % ( ''.join( traceback.format_tb( thread.exc_info[ 2 ] ) ), thread.exc_info[ 0 ].__name__, str( thread.exc_info[ 1 ] ) )
				MODULE.process( 'sending mail:An internal error occurred: %s' % msg )
				self.finished( request.id, False, msg, False )
コード例 #16
0
	def process_button(self):
#		if self._first_attempt_button:
#			self._first_attempt_button = False
#			raise UMC_Error(_('First try failed. Try again.'))
		MODULE.process('Generating new secret...')
		newkey_path = "/etc/openvpn/sitetosite.newkey"
		os.popen("openvpn --genkey --secret %s" % newkey_path)
		with open(newkey_path, 'r') as newkey_file:
			newkey=newkey_file.read().replace('\n', '<br />')
		return newkey
コード例 #17
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def _thread_finish_success( self, thread, result, request ):
		"""This method is invoked when a threaded request function is
		finished. The result is send back to the client. If the result
		is an instance of BaseException an error is returned."""
		if self._check_thread_error( thread, result, request ):
			return

		success, data = result
		MODULE.info( 'Got result from UVMMd: success: %s, data: %s' % ( success, data ) )
		self.finished( request.id, { 'success' : success, 'data' : data } )
コード例 #18
0
ファイル: __init__.py プロジェクト: kielfriedt/smart
    def _logstamp(self, fname):
        """ Logfile timestamp. Now a seperate function.
		"""
        try:
            st = stat(fname)
            if st:
                MODULE.info("   >> log file stamp = '%s'" % st[9])
                return st[9]
            return 0
        except:
            return 0
コード例 #19
0
ファイル: user.py プロジェクト: B-Rich/smart
	def _thread_finished(self, thread, thread_result, request):
		if not isinstance(thread_result, BaseException):
			request.status = SUCCESS
			self.finished(request.id, {'objects': thread_result['result'],
			                           'success': thread_result['success']},
			              thread_result['message'])
		else:
			message = str(thread_result) + '\n' + '\n'.join(thread.trace)
			MODULE.error('An internal error occurred: %s' % message)
			request.status = MODULE_ERR
			self.finished(request.id, None, message)
コード例 #20
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def _check_thread_error( self, thread, result, request ):
		"""Checks if the thread returned an exception. In that case in
		error response is send and the function returns True. Otherwise
		False is returned."""
		if not isinstance( result, BaseException ):
			return False

		msg = '%s\n%s: %s\n' % ( ''.join( traceback.format_tb( thread.exc_info[ 2 ] ) ), thread.exc_info[ 0 ].__name__, str( thread.exc_info[ 1 ] ) )
		MODULE.process( 'An internal error occurred: %s' % msg )
		self.finished( request.id, None, msg, False )
		return True
コード例 #21
0
ファイル: util.py プロジェクト: B-Rich/smart
	def calculateFractions( self ):
		MODULE.info( 'Calculating maximum value for fractions ...' )
		for category in filter( lambda x: os.path.isdir( os.path.join( PATH_SETUP_SCRIPTS, x ) ), os.listdir( PATH_SETUP_SCRIPTS ) ):
			cat_path = os.path.join( PATH_SETUP_SCRIPTS, category )
			for script in filter( lambda x: os.path.isfile( os.path.join( cat_path, x ) ), os.listdir( cat_path ) ):
				name = '%s/%s' % ( category, script )
				if not name in self.fractions:
					self.fractions[ name ] = 1

		self.current.max = sum( self.fractions.values() )
		MODULE.info( 'Calculated a maximum value of %d' % self.current.max )
コード例 #22
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def lang_timezones(self, request):
		'''Return a list of all available time zones.'''
		try:
			file = open('/lib/univention-installer/locale/timezone')
		except:
			MODULE.error( 'Cannot find locale data for timezones in /lib/univention-installer/locale' )
			self.finished(request.id, None)
			return

		timezones = [ i.strip('\n') for i in file if not i.startswith('#') ]

		self.finished(request.id, timezones)
コード例 #23
0
ファイル: server.py プロジェクト: m-narayan/smart
    def restart(self, request):
        """Restart apache, UMC Web server, and UMC server.
		"""
        # send a response immediately as it won't be sent after the server restarts
        self.finished(request.id, True)

        # enable server restart and trigger restart
        # (disable first to make sure the services are restarted)
        subprocess.call(CMD_DISABLE_EXEC)
        p = subprocess.Popen(CMD_ENABLE_EXEC_WITH_RESTART, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        out, err = p.communicate()
        MODULE.info("enabling server restart:\n%s" % out)
コード例 #24
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _return( pid, status, bufstdout, bufstderr, request, fn ):
			success = True
			if status == 0:
				univention.config_registry.handler_set( [ u'connector/ad/ldap/certificate=%s' % fn ] )
				message = _( 'Certificate has been uploaded successfully.' )
				MODULE.info( 'Certificate has been uploaded successfully. status=%s\nSTDOUT:\n%s\n\nSTDERR:\n%s' % ( status, '\n'.join( bufstdout ), '\n'.join( bufstderr ) ) )
			else:
				success = False
				message = _( 'Certificate upload or conversion failed.' )
				MODULE.process( 'Certificate upload or conversion failed. status=%s\nSTDOUT:\n%s\n\nSTDERR:\n%s' % ( status, '\n'.join( bufstdout ), '\n'.join( bufstderr ) ) )

			self.finished( request.id, [ { 'success' : success, 'message' : message } ] )
コード例 #25
0
ファイル: __init__.py プロジェクト: B-Rich/smart
		def _return( thread, result, request ):
			success = not result
			if result:
				message = _('Switching running state of Active Directory Connector failed.')
				MODULE.info( 'Switching running state of Active Directory Connector failed. exitcode=%s' % result )
			else:
				if request.options.get( 'action' ) == 'start':
					message = _( 'UCS Active Directory Connector has been started.' )
				else:
					message = _( 'UCS Active Directory Connector has been stopped.' )

			self.finished( request.id, { 'success' : success, 'message' : message } )
コード例 #26
0
ファイル: domains.py プロジェクト: B-Rich/smart
		def _finished( thread, result, request ):
			if self._check_thread_error( thread, result, request ):
				return

			success, data = result

			json = object2dict( data )
			MODULE.info( 'New domain: success: %s, data: %s' % ( success, json ) )
			if success:
				self.finished( request.id, json )
			else:
				self.finished( request.id, None, message = str( data ), status = MODULE_ERR_COMMAND_FAILED )
コード例 #27
0
ファイル: Users.py プロジェクト: B-Rich/smart
	def users_put(self, object):
		"""
			modify a local user
		"""

		response = []
		errors = {
			# no information about returncodes, yet
		}

		try:
			success = True
			message = ''

			# Username
			username = object.get('$username$')
			new_username = object.get('username')

			pwoptions = {}
			cmd = ['/usr/sbin/usermod']
			cmd += self._get_common_args( object, pwoptions )

			# Change username
			if username != new_username:
				cmd += ['-l', new_username]

			# Account deactivation
			if pwoptions.get('lock'):
				cmd.append('-L')

			elif object.get('unlock'):
				cmd.append('-U')

			# Password
			password = object.get('password')
			self._change_user_password(username, password, pwoptions)

			# Execute
			if len(cmd) > 1:
				cmd.append(username)
				returncode = self.process(cmd)
				if returncode != 0:
					MODULE.error("cmd '%s' failed with returncode %d" % (' '.join(map(str, cmd)) returncode))
					error = errors.get( returncode, _('unknown error with statuscode %d occurred') % (returncode) )
					raise ValueError( error )

		except ValueError as e:
			success = False
			message = '%s%s' % ('%s: ' % username if isinstance(username, basestring) else '', e,)

		MODULE.info( 'luga.users_edit: results: %s' % (message,) )
		return {'message': message, 'success': success}
コード例 #28
0
ファイル: Users.py プロジェクト: B-Rich/smart
	def users_add(self, object):
		"""
			add a local user
		"""

		errors = {
			1: _('could not update password file'),
			2: _('invalid command syntax'),
			3: _('invalid argument to option'),
			4: _('UID already in use (and no -o)'),
			6: _('specified group doesnt exist'),
			9: _('username already in use'),
			10: _('could not update group file'),
			12: _('could not create home directory'),
			13: _('could not create mail spool'),
		}

		try:
			success = True
			message = ''

			# Username
			username = object.get('username')

			pwoptions = {}
			cmd = ['/usr/sbin/useradd', '-r']

			if username == object.get('group'):
				object['create_usergroup'] = True
				cmd.append('-U')
			else:
				cmd.append('-N')

			cmd += self._get_common_args( object, pwoptions )

			# Execute
			cmd.append(username)
			returncode = self.process(cmd)
			if 0 != returncode:
				MODULE.error("cmd '%s' failed with returncode %d" % (' '.join(map(str, cmd)), returncode))
				error = errors.get( returncode, _('unknown error with statuscode %d occurred') % (returncode) )
				raise ValueError( error )

			# Change Password + options
			password = object.get('password')
			self._change_user_password(username, password, pwoptions)
		except ValueError as e:
			success = False
			message = '%s%s' % ('%s: ' % username if isinstance(username, basestring) else '', e,)

		MODULE.info( 'luga.users_add: results: %s' % (message,) )
		return {'message': message, 'success': success}
コード例 #29
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def net_dhclient(self, request):
		'''Request a DHCP address. Expects as options a dict containing the key
		"interface" and optionally the key "timeout" (in seconds).'''
		interface = request.options.get('interface')
		timeout = request.options.get('timeout', 45)
		if not interface:
			message = 'No property "interface" given for dhclient().'
			MODULE.error(message)
			self.finished(request.id, None, success = False, message = message)
			return

		res = util.dhclient(interface, timeout)
		self.finished(request.id, res)
コード例 #30
0
ファイル: __init__.py プロジェクト: B-Rich/smart
	def lang_keymaps(self, request):
		'''Return a list of all available keyboard layouts.'''
		try:
			file = open('/lib/univention-installer/locale/all-kmaps')
		except:
			MODULE.error( 'Cannot find locale data for keymaps in /lib/univention-installer/locale' )
			self.finished(request.id, None)
			return

		r = csv.reader(file, delimiter=':')
		keymaps = [ { 'label': i[0], 'id': i[1] } for i in r if not i[0].startswith('#') ]

		self.finished(request.id, keymaps)
コード例 #31
0
						def _finished(thread, result):
							if isinstance(result, BaseException):
								MODULE.warn('Exception during %s %s: %s' % (function, application_id, str(result)))
コード例 #32
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'))