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))
Esempio n. 4
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)
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()
	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
class UMCConnection(object):
	"""
	Connection to a |UMC| server.

	:param str hostname: The host name of the |UMC| server.
	:param str username: The user name.
	:param str password: The user password.
	:param error_handler: A function accepting the error message as the single argument.
	"""

	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

	@property
	def _headers(self):
		# type: () -> Dict[str, str]
		"""
		Return |HTTP| request headers.

		:returns: A dictionary containing the |HTTP| headers.
		:rtype: dict
		"""
		return self._client._headers

	@property
	def _host(self):
		# type: () -> str
		"""
		Return the host name of the |UMC| server,

		:returns: the host name.
		:rtype: str
		"""
		return self.client.hostname

	def get_connection(self):
		# type: () -> HTTPSConnection
		"""
		Return the underlying connection object.

		:returns: The connection.
		:rtype: HTTPSConnection
		"""
		return self._client._get_connection()

	@classmethod
	def get_machine_connection(cls, error_handler=None):
		# type: (Optional[Callable[[str], None]]) -> Optional[UMCConnection]
		"""
		Creates a connection with the credentials of the local host
		to the DC Master.

		:param error_handler: A function accepting the error message as the single argument.
		:returns: The connection object or None in case of errors.
		:rtype: UMCConnection
		"""
		try:
			connection = cls(ucr.get('ldap/master'))
			connection.client.authenticate_with_machine_account()
			return connection
		except ConnectionError as exc:
			if error_handler:
				error_handler('Could not connect to UMC on %s: %s' % (ucr.get('ldap/master'), exc.reason))

	def auth(self, username, password, auth_type=None):
		# type: (str, str, Optional[str]) -> None
		"""
		Tries to authenticate against the host and preserves the
		cookie. Has to be done only once (but keep in mind that the
		session probably expires after 10 minutes of inactivity)

		:param str username: The user name.
		:param str password: The user password.
		:param str auth_type: The authentication type, e.g. `???`.
		"""
		try:
			self.client.umc_auth(username, password, auth_type=auth_type)
		except HTTPError as exc:
			raise HTTPException(str(exc))

	def request(self, url, data=None, flavor=None, command='command'):
		# type: (str, Any, Optional[str], str) -> str
		"""
		Sends a request and returns the data from the response.

		:param str url: The partial |URL| of the |UMC| function to invoke. See the |XML| file of the |UMC| module.
		:param data: The data to send.
		:param flavor: Some |UMC| modules support flavors, e.g. the |UDM| module for sub-types.
		:param str command: may be anything that |UMCP| understands, especially:

			* `command` (default)
			* `get` (and `url` could be `ucr` then)
			* `set` (and `url` would be `` and `data` could be `{'locale':'de_DE'}`)
			* `upload` (`url` could be `udm/license/import`)

		:returns: the result of the response.
		:rtype: str
		"""
		if data is None:
			data = {}
		try:
			if command in ('command', 'upload'):
				response = self.client.umc_command(url, data, flavor)
			elif command == 'get':
				response = self.client.umc_get(url)
			elif command == 'set':
				response = self.client.umc_set(data)
		except Forbidden:
			raise NotImplementedError('command forbidden: %s' % url)
		except HTTPError as exc:
			if self._error_handler:
				self._error_handler(str(exc))
			raise HTTPException(str(exc))
		return response.result
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']
Esempio n. 10
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)
 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
class UMCConnection(object):
    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

    @property
    def _headers(self):
        return self._client._headers

    @property
    def _host(self):
        return self.client.hostname

    def get_connection(self):
        return self._client._get_connection()

    @classmethod
    def get_machine_connection(cls, error_handler=None):
        '''Creates a connection with the credentials of the local host
		to the DC Master'''
        try:
            connection = cls(ucr.get('ldap/master'))
            connection.client.authenticate_with_machine_account()
            return connection
        except ConnectionError as exc:
            if error_handler:
                error_handler('Could not connect to UMC on %s: %s' %
                              (ucr.get('ldap/master'), exc.reason))

    def auth(self, username, password, auth_type=None):
        '''Tries to authenticate against the host and preserves the
		cookie. Has to be done only once (but keep in mind that the
		session probably expires after 10 minutes of inactivity)'''
        try:
            self.client.umc_auth(username, password, auth_type=auth_type)
        except HTTPError as exc:
            raise HTTPException(str(exc))

    def request(self, url, data=None, flavor=None, command='command'):
        '''Sends a request and returns the data from the response. url
		as in the XML file of that UMC module.
		command may be anything that UMCP understands, especially:
		* command (default)
		* get (and url could be 'ucr' then)
		* set (and url would be '' and data could be {'locale':'de_DE'})
		* upload (url could be 'udm/license/import')
		'''
        if data is None:
            data = {}
        try:
            if command in ('command', 'upload'):
                response = self.client.umc_command(url, data, flavor)
            elif command == 'get':
                response = self.client.umc_get(url)
            elif command == 'set':
                response = self.client.umc_set(data)
        except Forbidden:
            raise NotImplementedError('command forbidden: %s' % url)
        except HTTPError as exc:
            if self._error_handler:
                self._error_handler(str(exc))
            raise HTTPException(str(exc))
        return response.result
Esempio n. 13
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. 14
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)
if options.samba not in ('3', '4'):
    parser.error('Samba version needs to be either 3 or 4!')

if ucr['server/role'] != 'domaincontroller_master' and not options.master:
    parser.error('Please specify a master host (-m)!')

if not options.username or not options.password:
    parser.error('Please specify username (-u) and password (-p)!')

if not options.ou:
    if ucr['server/role'] == 'domaincontroller_slave' or options.setup == 'singlemaster':
        parser.error('Please specify a school OU (-o)!')
    options.ou = ''

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

params = {
    'setup': options.setup,
    'username': options.username,
    'password': options.password,
    'master': options.master,
    'samba': options.samba,
    'schoolOU': options.ou,
}

if options.server_type:
    params['server_type'] = options.server_type
if options.name_edu_server:
    params['nameEduServer'] = options.name_edu_server
Esempio n. 16
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)
Esempio n. 17
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'))