コード例 #1
0
ファイル: computerroom.py プロジェクト: spaceone/ucs-school
class UmcComputer(object):
    def __init__(self,
                 school,
                 typ,
                 name=None,
                 ip_address=None,
                 subnet_mask=None,
                 mac_address=None,
                 inventory_number=None):
        self.school = school
        self.typ = typ
        self.name = name if name else uts.random_name()
        self.ip_address = ip_address if ip_address else random_ip()
        self.subnet_mask = subnet_mask if subnet_mask else '255.255.255.0'
        self.mac_address = mac_address.lower() if mac_address else random_mac()
        self.inventory_number = inventory_number if inventory_number else ''
        self.ucr = ucr_test.UCSTestConfigRegistry()
        self.ucr.load()
        host = self.ucr.get('ldap/master')
        self.client = Client(host)
        account = utils.UCSTestDomainAdminCredentials()
        admin = account.username
        passwd = account.bindpw
        self.client.authenticate(admin, passwd)

    def create(self, should_succeed=True):
        """Creates object Computer"""
        flavor = 'schoolwizards/computers'
        param = [{
            'object': {
                'school': self.school,
                'type': self.typ,
                'name': self.name,
                'ip_address': self.ip_address,
                'mac_address': self.mac_address.lower(),
                'subnet_mask': self.subnet_mask,
                'inventory_number': self.inventory_number
            },
            'options': None
        }]
        print 'Creating Computer %s' % (self.name, )
        print 'param = %s' % (param, )
        reqResult = self.client.umc_command('schoolwizards/computers/add',
                                            param, flavor).result
        if reqResult[0] == should_succeed:
            utils.wait_for_replication()
        elif should_succeed in reqResult[0]['result']['message']:
            print 'Expected creation fail for computer (%r)\nReturn Message: %r' % (
                self.name, reqResult[0]['result']['message'])
        else:
            raise CreateFail(
                'Unable to create computer (%r)\nRequest Result: %r' %
                (param, reqResult))

    def remove(self):
        """Remove computer"""
        flavor = 'schoolwizards/computers'
        param = [{
            'object': {
                '$dn$': self.dn(),
                'school': self.school,
            },
            'options': None
        }]
        reqResult = self.client.umc_command('schoolwizards/computers/remove',
                                            param, flavor).result
        if not reqResult[0]:
            raise RemoveFail('Unable to remove computer (%s)' % self.name)
        else:
            utils.wait_for_replication()

    def dn(self):
        return 'cn=%s,cn=computers,%s' % (
            self.name, utu.UCSTestSchool().get_ou_base_dn(self.school))

    def get(self):
        """Get Computer"""
        flavor = 'schoolwizards/computers'
        param = [{'object': {'$dn$': self.dn(), 'school': self.school}}]
        reqResult = self.client.umc_command('schoolwizards/computers/get',
                                            param, flavor).result
        if not reqResult[0]:
            raise GetFail('Unable to get computer (%s)' % self.name)
        else:
            return reqResult[0]

    def check_get(self):
        info = {
            '$dn$': self.dn(),
            'school': self.school,
            'type': self.typ,
            'name': self.name,
            'ip_address': [self.ip_address],
            'mac_address': [self.mac_address.lower()],
            'subnet_mask': self.subnet_mask,
            'inventory_number': self.inventory_number,
            'zone': None,
            'type_name': self.type_name(),
            'objectType': 'computers/%s' % self.typ
        }
        get_result = self.get()
        if get_result != info:
            diff = set(x for x in get_result if get_result[x] != info[x])
            raise GetCheckFail(
                'Failed get request for computer %s.\nReturned result: %r.\nExpected result: %r,\nDifference = %r'
                % (self.name, get_result, info, diff))

    def type_name(self):
        if self.typ == 'windows':
            return 'Windows-System'
        elif self.typ == 'macos':
            return 'Mac OS X'
        elif self.typ == 'ipmanagedclient':
            return 'Gerät mit IP-Adresse'

    def edit(self, new_attributes):
        """Edit object computer"""
        flavor = 'schoolwizards/computers'
        param = [{
            'object': {
                '$dn$':
                self.dn(),
                'name':
                self.name,
                'school':
                self.school,
                'type':
                self.typ,
                'ip_address':
                new_attributes.get('ip_address')
                if new_attributes.get('ip_address') else self.ip_address,
                'mac_address':
                new_attributes.get('mac_address').lower()
                if new_attributes.get('mac_address') else self.mac_address,
                'subnet_mask':
                new_attributes.get('subnet_mask')
                if new_attributes.get('subnet_mask') else self.subnet_mask,
                'inventory_number':
                new_attributes.get('inventory_number')
                if new_attributes.get('inventory_number') else
                self.inventory_number,
            },
            'options': None
        }]
        print 'Editing computer %s' % (self.name, )
        print 'param = %s' % (param, )
        reqResult = self.client.umc_command('schoolwizards/computers/put',
                                            param, flavor).result
        if not reqResult[0]:
            raise EditFail(
                'Unable to edit computer (%s) with the parameters (%r)' %
                (self.name, param))
        else:
            self.ip_address = new_attributes.get('ip_address')
            self.mac_address = new_attributes.get('mac_address').lower()
            self.subnet_mask = new_attributes.get('subnet_mask')
            self.inventory_number = new_attributes.get('inventory_number')
            utils.wait_for_replication()

    def query(self):
        """get the list of existing computer in the school"""
        flavor = 'schoolwizards/computers'
        param = {'school': self.school, 'filter': "", 'type': 'all'}
        reqResult = self.client.umc_command('schoolwizards/computers/query',
                                            param, flavor).result
        return reqResult

    def check_query(self, computers):
        q = self.query()
        k = [x['name'] for x in q]
        if not set(computers).issubset(set(k)):
            raise QueryCheckFail(
                'computers from query do not contain the existing computers, found (%r), expected (%r)'
                % (k, computers))

    def verify_ldap(self, should_exist):
        print 'verifying computer %s' % self.name
        utils.verify_ldap_object(self.dn(), should_exist=should_exist)
コード例 #2
0
ファイル: user.py プロジェクト: spaceone/ucs-school
class User(Person):
	"""Contains the needed functuality for users in the UMC module schoolwizards/users.\n
	:param school: school name of the user
	:type school: str
	:param role: role of the user
	:type role: str ['student', 'teacher', 'staff', 'teacherAndStaff']
	:param school_classes: dictionary of school -> list of names of the class which contain the user
	:type school_classes: dict
	"""

	def __init__(self, school, role, school_classes, mode='A', username=None, firstname=None, lastname=None, password=None, mail=None, schools=None):
		super(User, self).__init__(school, role)

		if username:
			self.username = username
			self.dn = self.make_dn()
		if firstname:
			self.firstname = firstname
		if lastname:
			self.lastname = lastname
		if mail:
			self.mail = mail
		if school_classes:
			self.school_classes = school_classes
		self.schools = schools or [self.school]
		self.typ = 'teachersAndStaff' if self.role == 'teacher_staff' else self.role
		self.mode = mode

		utils.wait_for_replication()
		self.ucr = ucr_test.UCSTestConfigRegistry()
		self.ucr.load()
		host = self.ucr.get('ldap/master')
		self.client = Client(host)
		account = utils.UCSTestDomainAdminCredentials()
		admin = account.username
		passwd = account.bindpw
		self.password = password if password else passwd
		self.client.authenticate(admin, passwd)

	def append_random_groups(self):
		pass

	def __enter__(self):
		return self

	def __exit__(self, type, value, trace_back):
		self.ucr.revert_to_original_registry()

	def create(self):
		"""Creates object user"""
		flavor = 'schoolwizards/users'
		param = [{
			'object': {
				'school': self.school,
				'schools': self.schools,
				'school_classes': self.school_classes,
				'email': self.mail,
				'name': self.username,
				'type': self.typ,
				'firstname': self.firstname,
				'lastname': self.lastname,
				'password': self.password
			},
			'options': None
		}]
		print '#### Creating user %s' % (self.username,)
		print '#### param = %s' % (param,)
		reqResult = self.client.umc_command('schoolwizards/users/add', param, flavor).result
		if not reqResult[0]:
			raise CreateFail('Unable to create user (%r)' % (param,))
		else:
			utils.wait_for_replication()

	def get(self):
		"""Get user"""
		flavor = 'schoolwizards/users'
		param = [{
			'object': {
				'$dn$': self.dn,
				'school': self.school
			}
		}]
		try:
			reqResult = self.client.umc_command('schoolwizards/users/get', param, flavor).result
		except BadRequest as exc:
			if exc.status == 400:
				reqResult = ['']
			else:
				raise
		if not reqResult[0]:
			raise GetFail('Unable to get user (%s)' % self.username)
		else:
			return reqResult[0]

	def check_get(self, expected_attrs={}):
		info = {
			'$dn$': self.dn,
			'display_name': ' '.join([self.firstname, self.lastname]),
			'name': self.username,
			'firstname': self.firstname,
			'lastname': self.lastname,
			'type_name': self.type_name(),
			'school': self.school,
			'schools': set(self.schools),
			'disabled': 'none',
			'birthday': None,
			'password': None,
			'type': self.typ,
			'email': self.mail,
			'objectType': 'users/user',
			'school_classes': {},
		}
		if self.is_student() or self.is_teacher() or self.is_teacher_staff():
			info.update({'school_classes': self.school_classes})

		if expected_attrs:
			info.update(expected_attrs)

		get_result = self.get()
		# Type_name is only used for display, Ignored
		info['type_name'] = get_result['type_name']
		# ignore OU order
		get_result['schools'] = set(get_result['schools'])
		if get_result != info:
			diff = []
			for key in (set(get_result.keys()) | set(info.keys())):
				if get_result.get(key) != info.get(key):
					diff.append('%s: Got:\n%r; expected:\n%r' % (key, get_result.get(key), info.get(key)))
			raise GetCheckFail('Failed get request for user %s:\n%s' % (self.username, '\n'.join(diff)))

	def type_name(self):
		if self.typ == 'student':
			return 'Student'
		elif self.typ == 'teacher':
			return 'Teacher'
		elif self.typ == 'staff':
			return 'Staff'
		elif self.typ == 'teacherAndStaff':
			return 'Teacher and Staff'

	def query(self):
		"""get the list of existing users in the school"""
		flavor = 'schoolwizards/users'
		param = {
			'school': self.school,
			'type': 'all',
			'filter': ""
		}
		reqResult = self.client.umc_command('schoolwizards/users/query', param, flavor).result
		return reqResult

	def check_query(self, users_dn):
		q = self.query()
		k = [x['$dn$'] for x in q]
		if not set(users_dn).issubset(set(k)):
			raise QueryCheckFail('users from query do not contain the existing users, found (%r), expected (%r)' % (
				k, users_dn))

	def remove(self, remove_from_school=None):
		"""Remove user"""
		remove_from_school = remove_from_school or self.school
		print('#### Removing User %r (%s) from school %r.' % (self.username, self.dn, remove_from_school))
		flavor = 'schoolwizards/users'
		param = [{
			'object': {
				'remove_from_school': remove_from_school,
				'$dn$': self.dn,
			},
			'options': None
		}]
		reqResult = self.client.umc_command('schoolwizards/users/remove', param, flavor).result
		if not reqResult[0]:
			raise RemoveFail('Unable to remove user (%s)' % self.username)
		else:
			schools = self.schools[:]
			schools.remove(remove_from_school)
			if not schools:
				self.set_mode_to_delete()
			else:
				self.update(school=sorted(schools)[0], schools=schools, mode='M')
				try:
					del self.school_classes[remove_from_school]
				except KeyError:
					pass

	def edit(self, new_attributes):
		"""Edit object user"""
		flavor = 'schoolwizards/users'
		object_props = {
			'school': self.school,
			'schools': self.schools,
			'email': new_attributes.get('email') if new_attributes.get('email') else self.mail,
			'name': self.username,
			'type': self.typ,
			'firstname': new_attributes.get('firstname') if new_attributes.get('firstname') else self.firstname,
			'lastname': new_attributes.get('lastname') if new_attributes.get('lastname') else self.lastname,
			'password': new_attributes.get('password') if new_attributes.get('password') else self.password,
			'$dn$': self.dn,
		}
		if self.typ not in ('teacher', 'staff', 'teacherAndStaff'):
			object_props['school_classes'] = new_attributes.get('school_classes', self.school_classes)

		param = [{
			'object': object_props,
			'options': None
		}]
		print '#### Editing user %s' % (self.username,)
		print '#### param = %s' % (param,)
		reqResult = self.client.umc_command('schoolwizards/users/put', param, flavor).result
		if not reqResult[0]:
			raise EditFail('Unable to edit user (%s) with the parameters (%r)' % (self.username, param))
		else:
			self.set_mode_to_modify()
			self.school_classes = new_attributes.get('school_classes', self.school_classes)
			self.mail = new_attributes.get('email') if new_attributes.get('email') else self.mail
			self.firstname = new_attributes.get('firstname') if new_attributes.get('firstname') else self.firstname
			self.lastname = new_attributes.get('lastname') if new_attributes.get('lastname') else self.lastname
			self.password = new_attributes.get('password') if new_attributes.get('password') else self.password
コード例 #3
0
class TestSamba4(object):
    def __init__(self):
        """
		Test class constructor
		"""
        self.UCR = ConfigRegistry()
        self.client = None

        self.admin_username = ''
        self.admin_password = ''

        self.ldap_master = ''

        self.gpo_reference = ''

    def return_code_result_skip(self):
        """
		Stops the test returning the code 77 (RESULT_SKIP).
		"""
        exit(TestCodes.REASON_INSTALL)

    def remove_samba_warnings(self, input_str):
        """
		Removes the Samba Warning/Note from the given input_str.
		"""
        # ignoring following messages (Bug #37362):
        input_str = input_str.replace(
            'WARNING: No path in service IPC$ - making it unavailable!', '')
        return input_str.replace('NOTE: Service IPC$ is flagged unavailable.',
                                 '').strip()

    def create_and_run_process(self,
                               cmd,
                               stdin=None,
                               std_input=None,
                               shell=False,
                               stdout=PIPE):
        """
		Creates a process as a Popen instance with a given 'cmd'
		and executes it. When stdin is needed, it can be provided with kwargs.
		To write to a file an istance can be provided to stdout.
		"""
        print '\n create_and_run_process(%r, shell=%r)' % (cmd, shell)
        proc = Popen(cmd,
                     stdin=stdin,
                     stdout=stdout,
                     stderr=PIPE,
                     shell=shell,
                     close_fds=True)

        stdout, stderr = proc.communicate(input=std_input)

        if stderr:
            stderr = self.remove_samba_warnings(stderr)
        if stdout:
            stdout = self.remove_samba_warnings(stdout)

        return stdout, stderr

    def start_stop_service(self, service, action):
        """
		Starts, stops or restarts the given 'service' depending on the given
		'action' is 'start', 'stop', 'restart' respectively.
		"""
        if action in ("start", "stop", "restart"):
            cmd = ("service", service, action)
            print "\nExecuting command:", cmd

            stdout, stderr = self.create_and_run_process(cmd)
            if stderr:
                utils.fail(
                    "An error occured during %sing the '%s' service: %s" %
                    (action, service, stderr))

            stdout = stdout.strip()
            if not stdout:
                utils.fail(
                    "The %s command did not produce any output to stdout, while a confirmation was expected"
                    % action)
            print stdout
        else:
            print(
                "\nUnknown state '%s' is given for the service '%s', accepted 'start' to start it 'stop' to stop or 'restart' to restart"
                % (action, service))

    def dc_master_has_samba4(self):
        """
		Returns 'True' when DC-Master has Samba4 according to "service=Samba 4"
		"""
        if not self.ldap_master:
            self.ldap_master = self.UCR.get('ldap/master')

        if self.ldap_master in self.get_udm_list_dcs('domaincontroller_master',
                                                     with_samba4=True):
            return True

    def is_a_school_branch_site(self, host_dn):
        """
		Returns True if the given 'host_dn' is located in the
		School branch site.
		"""
        if schoolldap.SchoolSearchBase.getOU(host_dn):
            return True

    def grep_for_key(self, grep_in, key):
        """
		Runs grep on given 'grep_in' with a given 'key'. Returns the output.
		"""
        stdout, stderr = self.create_and_run_process(("grep", key), PIPE,
                                                     grep_in)
        if stderr:
            utils.fail(
                "An error occured while running a grep with a keyword '%s':\n'%s'"
                % (key, stderr))
        return stdout

    def sed_for_key(self, input, key):
        """
		Runs sed on given 'input' with a given 'key'. Returns the output.
		"""
        cmd = ("sed", "-n", "s/%s//p" % (key, ))
        stdout, stderr = self.create_and_run_process(cmd, PIPE, input)
        if stderr:
            utils.fail(
                "An error occured while running a sed command '%s':\n'%s'" %
                (" ".join(cmd), stderr))
        return stdout

    def get_udm_list_dcs(self,
                         dc_type,
                         with_samba4=True,
                         with_ucsschool=False):
        """
		Runs the "udm computers/'dc_type' list" and returns the output.
		If 'with_samba4' is 'True' returns only those running Samba 4.
		"""
        if dc_type not in ('domaincontroller_master',
                           'domaincontroller_backup',
                           'domaincontroller_slave'):

            print "\nThe given DC type '%s' is unknown" % dc_type
            self.return_code_result_skip()

        cmd = ("udm", "computers/" + dc_type, "list")
        if with_samba4:
            cmd += ("--filter", "service=Samba 4")
        if with_ucsschool:
            cmd += ("--filter", "service=UCS@school")

        stdout, stderr = self.create_and_run_process(cmd)
        if stderr:
            utils.fail(
                "An error occured while running a '%s' command to find all '%s' in the domain:\n'%s'"
                % (" ".join(cmd), dc_type, stderr))
        return stdout

    def get_udm_list_dc_slaves_with_samba4(self, with_ucsschool=False):
        """
		Returns the output of "udm computers/domaincontroller_slave list
		--filter service=Samba 4" command.
		"""
        return self.get_udm_list_dcs("domaincontroller_slave",
                                     with_ucsschool=with_ucsschool)

    def select_school_ou(self, schoolname_only=False):
        """
		Returns the first found School OU from the list of DC-Slaves in domain.
		"""
        print "\nSelecting the School OU for the test"

        sed_stdout = self.sed_for_key(
            self.get_udm_list_dc_slaves_with_samba4(), "^DN: ")
        ous = [
            schoolldap.SchoolSearchBase.getOUDN(x) for x in sed_stdout.split()
        ]
        ous = [
            schoolldap.SchoolSearchBase.getOU(ou) if schoolname_only else ou
            for ou in ous if ou
        ]

        print "\nselect_school_ou: SchoolSearchBase found these OUs: %s" % (
            ous, )
        try:
            return ous[0]
        except IndexError:
            print "\nselect_school_ou: split: %s" % (sed_stdout.split(), )
            utils.fail(
                "Could not find the DN in the udm list output, thus cannot select the School OU to use as a container"
            )

    def get_samba_sam_ldb_path(self):
        """
		Returns the 'sam.ldb' path using samba conf or defaults.
		"""
        print(
            "\nObtaining the Samba configuration to determine Samba private path"
        )
        smb_conf_path = getenv("SMB_CONF_PATH")
        SambaLP = LoadParm()

        if smb_conf_path:
            SambaLP.load(smb_conf_path)
        else:
            SambaLP.load_default()

        return SambaLP.private_path('sam.ldb')

    def get_ucr_test_credentials(self):
        """
		Loads the UCR to get credentials for the test.
		"""
        print(
            "\nObtaining Administrator username and password for the test from the UCR"
        )
        try:
            self.UCR.load()

            self.admin_username = self.UCR['tests/domainadmin/account']
            # extracting the 'uid' value of the administrator username string:
            self.admin_username = self.admin_username.split(
                ',')[0][len('uid='):]
            self.admin_password = self.UCR['tests/domainadmin/pwd']
        except KeyError as exc:
            print(
                "\nAn exception while trying to read data from the UCR for the test: '%s'. Skipping the test."
                % exc)
            self.return_code_result_skip()

    def create_umc_connection_authenticate(self):
        """
		Creates UMC connection and authenticates to DC-Master with the test
		user credentials.
		"""
        if not self.ldap_master:
            self.ldap_master = self.UCR.get('ldap/master')

        try:
            self.client = Client(self.ldap_master, self.admin_username,
                                 self.admin_password)
        except (ConnectionError, HTTPError) as exc:
            print(
                "An HTTP Error occured while trying to authenticate to UMC: %r"
                % exc)
            print "Waiting 10 seconds and making another attempt"
            sleep(10)
            self.client.authenticate(self.admin_username, self.admin_password)

    def delete_samba_gpo(self):
        """
		Deletes the Group Policy Object using the 'samba-tool gpo del'.
		"""
        print(
            "\nRemoving previously created Group Policy Object (GPO) with a reference: %s"
            % self.gpo_reference)

        cmd = ("samba-tool", "gpo", "del", self.gpo_reference,
               "--username="******"--password="******"\nExecuting cmd:", cmd
            print(
                "\nAn error message while removing the GPO using 'samba-tool':\n%s"
                % stderr)

        print "\nSamba-tool produced the following output:\n", stdout
コード例 #4
0
ファイル: importcsv.py プロジェクト: spaceone/ucs-school
class CSVImport(object):
    """CSVImport class, inclues all the needed operations to perform a user import"""
    def __init__(self, school, user_type):
        self.school = school
        self.user_type = user_type
        self.ucr = ucr_test.UCSTestConfigRegistry()
        self.ucr.load()
        host = self.ucr.get('hostname')
        self.client = Client(host)
        account = utils.UCSTestDomainAdminCredentials()
        admin = account.username
        passwd = account.bindpw
        self.client.authenticate(admin, passwd)

    def genData(self, boundary, file_name, content_type, school, user_type,
                delete_not_mentioned):
        """Generates data in the form to be sent via http POST request.\n
		:param file_name: file name to be uploaded
		:type file_name: str
		:param content_type: type of the content of the file
		:type content_type: str  = 'text/csv'
		:param boundary: the boundary
		:type boundary: str (-------123091)
		:param flavor: flavor of the acting user
		:type flavor: str
		"""
        with open(file_name, 'r') as f:
            if delete_not_mentioned:
                data = r"""--{0}
Content-Disposition: form-data; name="uploadedfile"; filename="{1}"
Content-Type: {2}

{3}
--{0}
Content-Disposition: form-data; name="school"

{4}
--{0}
Content-Disposition: form-data; name="type"

{5}
--{0}
Content-Disposition: form-data; name="delete_not_mentioned"

true
--{0}
Content-Disposition: form-data; name="iframe"

false
--{0}
Content-Disposition: form-data; name="uploadType"

html5
--{0}--
""".format(boundary, file_name, content_type, f.read(), school, user_type)
            else:
                data = r"""--{0}
Content-Disposition: form-data; name="uploadedfile"; filename="{1}"
Content-Type: {2}

{3}
--{0}
Content-Disposition: form-data; name="school"

{4}
--{0}
Content-Disposition: form-data; name="type"

{5}
--{0}
Content-Disposition: form-data; name="iframe"

false
--{0}
Content-Disposition: form-data; name="uploadType"

html5
--{0}--
""".format(boundary, file_name, content_type, f.read(), school, user_type)
        return data.replace("\n", "\r\n")

    def uploadFile(self, file_name, content_type, delete_not_mentioned,
                   expected_upload_status):
        """Uploads a file via http POST request.\n
		:param file_name: file name to be uploaded
		:type file_name: str
		:param content_type: type of the content of the file
		:type content_type: str ('text/csv')
		"""
        print 'Uploading file %r' % file_name
        boundary = '---------------------------18209455381072592677374099768'
        data = self.genData(boundary, file_name, content_type, self.school,
                            self.user_type, delete_not_mentioned)

        header_content = {
            'Content-Type': 'multipart/form-data; boundary=%s' % (boundary, )
        }

        try:
            response = self.client.request('POST',
                                           'upload/schoolcsvimport/save',
                                           data,
                                           headers=header_content)
        except HTTPError as exc:
            response = exc.response
        status = response.status
        if status != expected_upload_status:
            raise FailHTTPStatus('Unexpected response status=%r' % status)
        elif status == 200:
            self.file_id = response.result[0]['file_id']
            self.id_nr = 1
        else:
            print 'Expected http_status = %r' % status
        return status

    def show(self):
        param = {
            'file_id':
            self.file_id,
            'columns': [
                "name", "firstname", "lastname", "birthday", "password",
                "email", "school_classes"
            ],
        }
        if self.user_type == 'staff':
            param['columns'].remove('school_classes')
        try:
            reqResult = self.client.umc_command('schoolcsvimport/show',
                                                param).result
            self.id_nr = reqResult['id']
        except FailShow:
            raise

    def progress(self):
        param = {'progress_id': self.id_nr}
        try:
            reqResult = self.client.umc_command('schoolcsvimport/progress',
                                                param).result
        except FailProgress:
            raise
        return reqResult

    def recheck(self, user):
        param = {'file_id': self.file_id, 'user_attrs': [user]}
        try:
            reqResult = self.client.umc_command('schoolcsvimport/recheck',
                                                param).result
            print 'RECHECK RESULT = ', reqResult
            return reqResult
        except FailRecheck:
            raise

    def schools(self):
        try:
            reqResult = self.client.umc_command('schoolcsvimport/schools',
                                                {}).result
        except FailSchools:
            raise
        return [x['id'] for x in reqResult]

    def check_schools(self):
        if self.school not in self.schools():
            raise FailSchools(
                'School %s not found by request: schoolcsvimport/schools' %
                (self.school))

    def write_import_file(self, filename, lines, has_header=True):
        with open(filename, 'wb') as f:
            f.write(''.join(lines))
            f.flush()

    def read_import_file(self, filename, has_header=True):
        with open(filename, 'rb') as f:
            lines = f.readlines()
        if has_header:
            columns = lines[0][:-1].split(',')
            lines = lines[1:]
        else:
            columns = []
        lines = [x[:-1] for x in lines]
        return lines, columns

    def import_users(self, users):
        line_nr = 1
        param = []

        def get_type_name(typ):
            if typ == 'cSVStudent':
                return 'Student'
            elif typ == 'cSVTeacher':
                return 'Teacher'
            elif typ == 'cSVStaff':
                return 'Staff'
            elif typ == 'cSVTeachersAndStaff':
                return 'Teacher and Staff'

        for user in users:
            user.update({'line': line_nr})
            user.update({'type_name': get_type_name(user['type'])})
            options = {'file_id': self.file_id, 'attrs': user}
            line_nr += 1
            param.append(options)
        try:
            pprint(('Importing users with parameters=', param))
            reqResult = self.client.umc_command('schoolcsvimport/import',
                                                param).result
            self.id_nr = reqResult['id']
            utils.wait_for_replication()
        except FailImport:
            raise