Пример #1
0
    def service_stop(self, service):
        """ stop service """
        logFull('CeServices:service_stop')

        rc = self.service_status(service)
        if not rc:
            logDebug('SM: Service name `{}` is not running.'.format(service['name']))
            return False

        tprocess = service.get('pid', 0)

        if isinstance(tprocess, int):
            logError('SM: Cannot stop service `{}`!'.format(service['name']))

        try:
            tprocess.terminate()
        except Exception as exp_err:
            logError('SM: Cannot stop service: `{}`, exception `{}`!'.format(service['name'], exp_err))
            return False

        try:
            time.sleep(0.1)
            os.killpg(tprocess.pid, signal.SIGTERM)
            time.sleep(0.1)
            tprocess.kill()
        except:
            pass

        logWarning('SM: Stopped service: `{}`.'.format(service['name']))
        return True
Пример #2
0
 def reset_user(self, user):
     """ clean user related information """
     logFull('CeWebUi:reset_user user `{}`.'.format(user))
     self.project.reset_project(user)
     self.project.reset_logs(user)
     raise cherrypy.HTTPRedirect('http://{host}/web/users/{user}'.\
     format(host=cherrypy.request.headers['Host'], user=user))
Пример #3
0
 def list_services(self):
     """ return list of services """
     logFull('CeServices:list_services')
     srv = []
     for service in self.twister_services:
         srv.append(service['name'])
     return ','.join(srv)
Пример #4
0
    def get_binding(self, fpath):
        """
        Read a binding between a CFG and a SUT.
        The result is XML.
        """
        logFull('xmlparser:get_binding')
        cfg_file = '{}/twister/config/bindings.xml'.format(userHome(self.user))

        if not os.path.isfile(cfg_file):
            err = '*ERROR* Bindings Config file `{}`, for user `{}` does not exist!'.format(cfg_file, self.user)
            logError(err)
            return err

        bind_xml = parseXML(self.user, cfg_file)
        if bind_xml is None:
            err = '*ERROR* Config file `{}`, for user `{}` cannot be parsed!'.format(cfg_file, self.user)
            return err
        # Find the old binding
        found = bind_xml.xpath('/root/binding/name[text()="{}"]/..'.format(fpath))

        if found:
            xml_string = etree.tostring(found[0])
            return xml_string.replace('binding>', 'root>')
        else:
            logWarning('*ERROR* Cannot find binding name `{}` for user {}!'.format(fpath, self.user))
            return False
Пример #5
0
    def get_resource(self, query, resource=None):
        """
        Get the resource from resource by path or id.
        We can search for query in self.resources or in any other resource given as parameter.
        """
        logFull("CeCommonAllocator: Getting the resource {}".format(query))

        if not resource:
            resource = self.resources

        if not resource or not query:
            msg = 'Cannot get a null resource {} or a new query {}!'.format(
                resource, query)
            logError(msg)
            return False

        if ':' in query:
            query = query.split(':')[0]

        # If the query is an ID
        if '/' not in query:
            result = self.get_id(query, resource)
        else:
            result = self.get_path(query, resource)

        if result:
            return dict(result)

        return result
Пример #6
0
    def getBindingsConfig(self):
        """
        Parse the bindings file that connects Roots from a config file, with SUTs.
        """
        logFull('xmlparser:getBindingsConfig')
        cfg_file = '{}/twister/config/bindings.xml'.format(userHome(self.user))
        bindings = {}

        if not os.path.isfile(cfg_file):
            err = '*ERROR* Bindings Config file `{}`, for user `{}` does not exist!'.format(cfg_file, self.user)
            logError(err)
            return err

        bind_xml = parseXML(self.user, cfg_file)
        if bind_xml is None:
            err = '*ERROR* Config file `{}`, for user `{}` cannot be parsed!'.format(cfg_file, self.user)
            return err

        for binding in bind_xml.xpath('/root/binding'):
            name = binding.find('name')
            # Valid names ?
            if name is None:
                continue
            name = name.text.strip()
            if not name:
                continue
            bindings[name] = {}
            # All binds cfg -> sut
            for bind in binding.findall('bind'):
                cfg = bind.get('config')
                sut = bind.get('sut')
                bindings[name][cfg] = sut

        logDebug('Found `{}` bindings for user `{}`.'.format(len(bindings), self.user))
        return bindings
Пример #7
0
    def json_save_project(self, user, epname):
        """ save project """
        logFull('CeWebUi:json_save_project user `{}`.'.format(user))
        if self.user_agent() == 'x':
            return 0

        c_l = cherrypy.request.headers['Content-Length']
        raw_data = cherrypy.request.body.read(int(c_l))
        json_data = json.loads(raw_data)
        del c_l, raw_data

        # Delete everything from XML Root
        self.project.del_settings_key(user, 'project', '//TestSuite')
        changes = 'Reset project file...\n'

        for suite_data in json_data:
            self.project.set_persistent_suite(user, suite_data['data'],
                                              {'ep': decode(epname)})
            changes += 'Created suite: {0}.\n'.format(suite_data['data'])
            for file_data in suite_data.get('children', []):
                changes += 'Created file: {0}.\n'.format(file_data['data'])
                self.project.set_persistent_file(user, suite_data['data'],
                                                 file_data['data'], {})

        changes += '>.<\n'
        logDebug(changes)
        return 'true'
Пример #8
0
    def save_release_reserved_tb(self, res_query, props={}):
        """
        Save the changes. Sync self.resources with self.reserved_resources
        and save to the disk
        """
        logDebug('CeTestBeds:save_release_reserved_tb {} {}'.format(res_query, props))

        # save changes
        result = self.save_reserved_tb(res_query, props)

        if result and not result.startswith("*ERROR*"):
            user_info = self.user_info(props)

            if ':' in res_query:
                res_query = res_query.split(':')[0]

            # get only the component
            resource_node = self.get_resource(res_query)
            if not resource_node or isinstance(resource_node, str):
                logFull("Can not find the resoruce {}".format(res_query))
                return None

            # get the entire TB
            if len(resource_node['path']) > 1:
                resource_node = self.get_path(resource_node['path'][0], self.resources)

            # delete this entry from reservedResources
            reserved_node = self.reservedResources[user_info[0]][resource_node['id']]
            self.reservedResources[user_info[0]].pop(reserved_node['id'])
            if not self.reservedResources[user_info[0]]:
                self.reservedResources.pop(user_info[0])
        else:
            return result

        return True
Пример #9
0
def setFileOwner(user, path):
    """
    Update file ownership for 1 file or folder.\n
    `Chown` function works ONLY in Linux.
    """
    logFull('helpers:setFileOwner user `{}`.'.format(user))
    try:
        from pwd import getpwnam
        uid = getpwnam(user)[2]
        gid = getpwnam(user)[3]
    except:
        return False

    if os.path.isdir(path):
        try:
            proc = subprocess.Popen(
                ['chown',
                 str(uid) + ':' + str(gid), path, '-R', '--silent'], )
            proc.wait()
        except:
            logWarning(
                'Cannot change owner! Cannot chown folder `{}:{}` on `{} -R`!'.
                format(uid, gid, path))
            return False

    else:
        try:
            os.chown(path, uid, gid)
        except:
            logWarning(
                'Cannot set owner! Cannot chown file `{}:{}` on `{}`!'.format(
                    uid, gid, path))
            return False

    return True
Пример #10
0
    def users(self, user=''):
        """ list all users """
        logFull('CeWebUi:users')
        if self.user_agent() == 'x':
            return 0
        if not user:
            raise cherrypy.HTTPRedirect('/web/#tab_users')

        host = cherrypy.request.headers['Host']
        rev_dict = dict((v, k) for k, v in EXEC_STATUS.iteritems())
        int_status = self.project.get_user_info(user,
                                                'status') or STATUS_INVALID
        status = rev_dict[int_status]
        try:
            eps_file = self.project.parsers[user].project_globals['ep_names']
        except:
            eps_file = ''

        eps = self.project.get_user_info(user, 'eps')
        ep_statuses = [rev_dict[eps[ep].get('status', STATUS_INVALID)] \
        for ep in eps]
        logs = self.project.get_user_info(user, 'log_types')

        output = Template(filename=TWISTER_PATH +
                          '/server/template/rest_user.htm')
        return output.render(host=host, user=user, status=status,\
        exec_status=rev_dict, eps_file=eps_file, eps=eps,\
        ep_statuses=ep_statuses, logs=logs)
Пример #11
0
    def del_binding(self, fpath):
        """
        Delete a binding between a CFG and a SUT.
        Return True/ False.
        """
        logFull('xmlparser:del_binding')
        cfg_file = '{}/twister/config/bindings.xml'.format(userHome(self.user))

        if not os.path.isfile(cfg_file):
            err = '*ERROR* Bindings Config file `{}`, for user `{}` does not exist!'.format(cfg_file, self.user)
            logError(err)
            return err

        bind_xml = parseXML(self.user, cfg_file)
        if bind_xml is None:
            err = '*ERROR* Config file `{}`, for user `{}` cannot be parsed!'.format(cfg_file, self.user)
            return err
        # Find the binding
        found = bind_xml.xpath('/root/binding/name[text()="{}"]/..'.format(fpath))

        # If found, delete it
        if found:
            bind_xml.remove(found[0])
            logDebug('Removed binding `{}`, for user `{}`.'.format(fpath, self.user))
        else:
            err = '*WARN* Invalid binding `{}`, user `{}`! Cannot unbind!'.format(fpath, self.user)
            # logDebug(err)
            return False

        return dumpXML(self.user, cfg_file, bind_xml)
Пример #12
0
    def getFileInfo(self, file_soup):
        """
        Returns a dict with information about 1 File from Test-Suites XML.
        The "file" must be a XML class.
        """
        logFull('xmlparser:getFileInfo')

        res = OrderedDict()
        res['type'] = 'file'
        # Get File ID from testsuites.xml
        res['id'] = file_soup.xpath('ID')[0].text
        # The second parameter is the Suite name
        res['suite'] = file_soup.getparent().xpath('id')[0].text

        # Parse all known File Tags
        for tag_dict in TESTS_TAGS:
            # Create default entry
            res[tag_dict['name']] = tag_dict['default']
            # Exception for config files
            if tag_dict['name'] == '_cfg_files':
                cfg_files = []
                for cfg_soup in file_soup.xpath(tag_dict['tag']):
                    if cfg_soup.get('enabled').lower() == 'true':
                        cfg = {
                            'name': cfg_soup.get('name'),
                            'iter_default': cfg_soup.get('iterator_default'),
                            'iter_sof': cfg_soup.get('iterator_sof')
                        }
                        cfg_files.append(cfg)
                if cfg_files:
                    res[tag_dict['name']] = cfg_files
            # Update value from XML
            elif file_soup.xpath(tag_dict['tag'] + '/text()'):
                value = file_soup.xpath(tag_dict['tag'])[0].text
                if not value.strip():
                    continue
                res[tag_dict['name']] = value

        # Inject this empty variable
        res['twister_tc_revision'] = '-1'

        # Add property/ value tags
        prop_keys = file_soup.xpath('Property/propName')
        prop_vals = file_soup.xpath('Property/propValue')
        params = ''

        # The order of the properties is important!
        for i in range(len(prop_keys)):
            p_key = prop_keys[i].text
            p_val = prop_vals[i].text

            # Param tags are special
            if p_key == 'param':
                params += p_val + ','
                p_val = params
            res[p_key] = p_val

        return res
Пример #13
0
def systemInfo():
    """
    Returns some system information.
    """
    logFull('helpers:systemInfo')
    system = platform.machine() + ' ' + platform.system() + ', ' + ' '.join(
        platform.linux_distribution())
    python = '.'.join([str(v) for v in sys.version_info])
    return '{}\nPython {}'.format(system.strip(), python)
Пример #14
0
    def get_query(self, field_id):
        """
        Used by the applet.
        """
        logFull('dbparser:get_query')
        res = self.user_xml.xpath('insert_section/field[@ID="%s"]' % field_id)
        if not res:
            logWarning('User {}: Cannot find field ID `{}`!'.format(self.user, field_id))
            return False

        query = res[0].get('SQLQuery')
        return query
Пример #15
0
    def json_get_project(self):
        """ get the project """
        logFull('CeWebUi:json_get_project')
        if self.user_agent() == 'x':
            return 0

        cherrypy.response.headers[
            'Content-Type'] = 'application/json; charset=utf-8'
        cherrypy.response.headers[
            'Cache-Control'] = 'no-cache, no-store, must-revalidate'
        cherrypy.response.headers['Pragma'] = 'no-cache'
        cherrypy.response.headers['Expires'] = 0
        return open(TWISTER_PATH + '/config/project_users.json', 'r').read()
Пример #16
0
    def save_config(self, service, data):
        """ Save configuration """
        logFull('CeServices:save_config')

        config_path = '{0}/services/{1}/{2}'.format(TWISTER_PATH, service['name'], service['config'])

        if not os.path.isfile(config_path):
            logError('SM: No such config file `{0}`!'.format(config_path))
            return False

        with open(config_path, 'wb') as out:
            out.write(data)

        return True
Пример #17
0
    def json_stats(self):
        """ get stats """
        logFull('CeWebUi:json_stats')
        if self.user_agent() == 'x':
            return 0

        cherrypy.response.headers[
            'Content-Type'] = 'application/json; charset=utf-8'
        cherrypy.response.headers[
            'Cache-Control'] = 'no-cache, no-store, must-revalidate'
        cherrypy.response.headers['Pragma'] = 'no-cache'
        cherrypy.response.headers['Expires'] = 0
        data = {'mem': calcMemory(), 'cpu': calcCpu()}
        return json.dumps(data)
Пример #18
0
    def read_config(self, service):
        """ Read configuration """
        logFull('CeServices:read_config')

        config_path = '{0}/services/{1}/{2}'.format(TWISTER_PATH, service['name'], service['config'])

        if not os.path.isfile(config_path):
            logError('SM: No such config file `{0}`!'.format(config_path))
            return False

        with open(config_path, 'rb') as out:
            data = out.read()

        return data or ''
Пример #19
0
    def send_command(self, command, name='', *args, **kwargs):
        """ send command to service """
        logFull('CeServices:send_command')

        if command == SM_LIST or command == SM_COMMAND_MAP[SM_LIST]:
            return self.list_services()

        found = False

        service = None
        for service_item in self.twister_services:
            if name == service_item['name']:
                found = True
                service = service_item
                break

        if not found:
            logDebug('SM: Invalid service name: `{}`!'.format(name))
            return False

        elif command == SM_STATUS or command == SM_COMMAND_MAP[SM_STATUS]:
            return self.service_status(service)

        elif command == SM_DESCRIP or command == SM_COMMAND_MAP[SM_DESCRIP]:
            return service.get('descrip')

        if command == SM_START or command == SM_COMMAND_MAP[SM_START]:
            return self.service_start(service)

        elif command == SM_STOP or command == SM_COMMAND_MAP[SM_STOP]:
            return self.service_stop(service)

        elif command == SM_GET_CONFIG or command == SM_COMMAND_MAP[SM_GET_CONFIG]:
            return self.read_config(service)

        elif command == SM_SET_CONFIG or command == SM_COMMAND_MAP[SM_SET_CONFIG]:
            try:
                return self.save_config(service, args[0][0])
            except:
                return 'SM: Invalid number of parameters for save config!'

        elif command == SM_GET_LOG or command == SM_COMMAND_MAP[SM_GET_LOG]:
            try:
                return self.get_console_log(service, read=args[0][0], fstart=args[0][1])
            except:
                return 'SM: Invalid number of parameters for read log!'

        else:
            return 'SM: Unknown command number: `{0}`!'.format(command)
Пример #20
0
 def list_settings(self, xmlFile, xFilter=''):
     """
     High level function for listing all settings from a Twister XML config file.
     """
     logFull('xmlparser:list_settings')
     if not os.path.isfile(xmlFile):
         logError('User {}: Parse settings error! File path `{}` does not exist!'.format(self.user, xmlFile))
         return False
     xmlSoup = parseXML(self.user, xmlFile)
     if xmlSoup is None:
         return []
     if xFilter:
         return [x.tag for x in xmlSoup.xpath('//*') if xFilter in x.tag]
     else:
         return [x.tag for x in xmlSoup.xpath('//*')]
Пример #21
0
def encrypt(bdata, encr_key):
    """
    Encrypt some data.
    """
    logFull('helpers:encrypt')
    # Enhance user password with PBKDF2
    pwd = PBKDF2(password=encr_key,
                 salt='^0Twister-Salt9$',
                 dkLen=32,
                 count=100)
    crypt = AES.new(pwd)
    pad_len = 16 - (len(bdata) % 16)
    padding = (chr(pad_len) * pad_len)
    # Encrypt user data + correct padding
    data = crypt.encrypt(bdata + padding)
    return binascii.hexlify(data)
Пример #22
0
 def _fixLogType(self, logType):
     """
     Helper function to fix log names.
     """
     logFull('xmlparser:_fixLogType')
     if logType.lower() == 'logrunning':
         logType = 'logRunning'
     elif logType.lower() == 'logdebug':
         logType = 'logDebug'
     elif logType.lower() == 'logsummary':
         logType = 'logSummary'
     elif logType.lower() == 'logtest':
         logType = 'logTest'
     elif logType.lower() == 'logcli':
         logType = 'logCli'
     return logType
Пример #23
0
    def del_settings_key(self, xmlFile, key, index=0):
        """
        High level function for deleting a value from a Twister XML config file.
        If the `index` is specified and the `key` returns more values, only the
        index-th value is deleted; unless the `index` is -1, in this case, all
        values are deleted.
        """
        logFull('xmlparser:del_settings_key')
        if not os.path.isfile(xmlFile):
            logError('User {}: Parse settings error! File path `{}` does not exist!'.format(self.user, xmlFile))
            return False
        # The key must be string
        if not (isinstance(key, str) or isinstance(key, unicode)):
            return False
        # The index must be integer
        if not isinstance(index, int):
            return False
        # The key must not be Null
        if not key:
            return False
        else:
            key = str(key)

        xmlSoup = parseXML(self.user, xmlFile)
        if xmlSoup is None:
            return False
        xml_key = xmlSoup.xpath(key)

        if xml_key is None:
            return False

        # For index -1, delete all matches
        if index == -1:
            for xml_v in xml_key:
                xml_parent = xml_v.getparent()
                xml_parent.remove(xml_v)
        else:
            # Use the index-th occurence, or, if the index is wrong, exit
            try:
                xml_key = xml_key[index]
            except Exception:
                return False

            xml_parent = xml_key.getparent()
            xml_parent.remove(xml_key)

        return dumpXML(self.user, xmlFile, xmlSoup)
Пример #24
0
    def service_status(self, service):
        """ return status of service """
        logFull('CeServices:service_status')
        # Values are: -1, 0, or any error code
        # -1 means the app is still running

        tprocess = service.get('pid', 0)
        retc = 0

        if tprocess:
            tprocess.poll()
            retc = tprocess.returncode

        if retc is None:
            retc = -1

        return retc
Пример #25
0
    def is_resource_reserved(self, res_query, props={}):
        """
        Verify if a resource is already reserved.
        Returns the user or false.
        """

        logFull(
            'CeCommonAllocator:is_resource_reserved: res_query = {}'.format(
                res_query))

        resources = self.resources
        if '/' not in res_query:
            res_for_user = [
                u for u in self.reservedResources
                if res_query in self.reservedResources[u]
            ]

        if '/' in res_query or not res_for_user:
            #if res_query contains components unsaved yet, search only for the TB
            if '/' in res_query:
                parts = [q for q in res_query.split('/') if q]
                node_path = self.get_resource('/' + parts[0])
            else:
                node_path = self.get_resource(res_query)

            if not node_path or isinstance(node_path, str):
                msg = "No such resource {}".format(res_query)
                logError(msg)
                return False

            if isinstance(node_path['path'],
                          list) and len(node_path['path']) > 1:
                node_path = self.get_path(node_path['path'][0], resources)
                if not node_path and isinstance(node_path, str):
                    msg = "No such resource {}".format(res_query)
                    logError(msg)
                    return False

            res_for_user = [
                u for u in self.reservedResources
                if node_path['id'] in self.reservedResources[u]
            ]

        if not res_for_user:
            return False
        return res_for_user[0]
Пример #26
0
    def getEmailConfig(self, eml_file=''):
        """
        Returns the e-mail configuration.
        After Central Engine stops, an e-mail must be sent to the people interested.
        """
        logFull('xmlparser:getEmailConfig')
        if not eml_file:
            eml_file = self.project_globals['eml_config']

        if not os.path.isfile(eml_file):
            logError('User {}: Parser: E-mail Config file `{}` does not exist!'.format(self.user, eml_file))
            return {}

        econfig = parseXML(self.user, eml_file)
        if econfig is None:
            return {}

        res = {}
        res['Enabled'] = ''
        res['SMTPPath'] = ''
        res['SMTPUser'] = ''
        res['SMTPPwd'] = ''
        res['From'] = ''
        res['To'] = ''
        res['Subject'] = ''
        res['Message'] = ''

        if econfig.xpath('Enabled/text()'):
            res['Enabled'] = econfig.xpath('Enabled')[0].text
        if econfig.xpath('SMTPPath/text()'):
            res['SMTPPath'] = econfig.xpath('SMTPPath')[0].text
        if econfig.xpath('SMTPUser/text()'):
            res['SMTPUser'] = econfig.xpath('SMTPUser')[0].text
        if econfig.xpath('SMTPPwd/text()'):
            res['SMTPPwd'] = econfig.xpath('SMTPPwd')[0].text

        if econfig.xpath('From/text()'):
            res['From'] = econfig.xpath('From')[0].text
        if econfig.xpath('To/text()'):
            res['To'] = econfig.xpath('To')[0].text
        if econfig.xpath('Subject/text()'):
            res['Subject'] = econfig.xpath('Subject')[0].text
        if econfig.xpath('Message/text()'):
            res['Message'] = econfig.xpath('Message')[0].text
        return res
Пример #27
0
    def set_settings_value(self, xmlFile, key, value):
        """
        High level function for setting a value in a Twister XML config file.
        """
        logFull('xmlparser:set_settings_value')
        if not os.path.isfile(xmlFile):
            logError('User {}: Parse settings error! File path `{}` does not exist!'.format(self.user, xmlFile))
            return False
        if not key:
            return False
        else:
            key = str(key)
        if not value:
            value = ''
        else:
            value = str(value)

        xmlSoup = parseXML(self.user, xmlFile)
        if xmlSoup is None:
            return False
        xml_key = xmlSoup.xpath(key)

        # If the key is found, update it
        if xml_key:
            xml_key[0].text = value

        # Else, create it
        else:
            # Try and split the key into parent and node
            if '/' in key:
                parent_path, node_name = '/'.join(key.split('/')[:-1]), key.split('/')[-1]
            else:
                parent_path, node_name = '/', key
            parent = xmlSoup.xpath(parent_path)
            # Invalid parent path ?
            if not parent:
                return False

            # Create the new node
            node = etree.Element(node_name)
            node.text = value
            node.tail = '\n'
            parent[0].insert(-1, node)

        return dumpXML(self.user, xmlFile, xmlSoup)
Пример #28
0
    def create_new_tb(self, name, parent=None, props={}):
        """
        Create new test bed.
        Return the id of the new created tb.
        """

        user_info = self.user_info(props)
        resources = self.resources

        if parent != '/' and parent != '1':
            msg = "The parent value is not root. Maybe you want to add a component\
             to an existing SUT. Parent: {}".format(parent)
            logError(msg)
            return "*ERROR* " + msg

        props = self.valid_props(props)

        with self.acc_lock:
            # root can not be reserved so we just take it
            parent_p = self.get_resource('/', resources)

            if not parent_p or isinstance(parent_p, str):
                logFull("User: {} no result for query `{}`" .format(user_info[0], parent))
                return None

            if '/' in name:
                logDebug('Stripping slash characters from `{}`...'.format(name))
                name = name.replace('/', '')

            if name in self.resources['children']:
                msg = "User {}: A TB with name `{}` already exists!".format(user_info[0], name)
                logDebug(msg)
                return "*ERROR* " + msg

            # the resource doesn't exist - create it
            res_id = self.generate_index()
            parent_p['children'][name] = {'id': res_id, 'meta': props, 'children': {}, 'path': [name]}

            issaved = self.save_tb(props)
            if not issaved:
                msg = "User {}: Could not save TB `{}`".format(user_info[0], name)
                logDebug(msg)
                return "*ERROR* " + msg

            return res_id
Пример #29
0
    def change_path(self, result, path):
        '''
        update the path of all kids if the result is renamed for example
        '''

        logFull("CeCommonAllocator: change_path  {} ".format(path))
        if not result:
            return False
        if not result.get('children'):
            return True

        for node in result.get('children'):
            result['children'][node]['path'] = path + [node]
            self.change_path(result['children'][node],
                             result['children'][node]['path'])

        if not result:
            return True
Пример #30
0
    def updateProjectGlobals(self):
        """
        Returns the values of many global tags, from FWM and Test-Suites XML.
        """
        logFull('xmlparser:updateProjectGlobals')
        if self.configTS is None:
            logError('User {}: Parser: Cannot get project globals, because'\
            ' Test-Suites XML is invalid!'.format(self.user))
            return False

        # Reset globals
        self.project_globals = OrderedDict()

        # Parse all known FWMCONFIG tags
        for tag_dict in FWMCONFIG_TAGS:
            # Create default entry
            self.project_globals[tag_dict['name']] = tag_dict['default']
            # Update value from XML
            if self.xmlDict.xpath(tag_dict['tag'] + '/text()'):
                path = self.xmlDict.xpath(tag_dict['tag'])[0].text
                if path[0] == '~':
                    path = self.user_home + path[1:]
                self.project_globals[tag_dict['name']] = path

        # Parse all known PROJECT tags
        for tag_dict in PROJECTCONFIG_TAGS:
            # Create default entry
            self.project_globals[tag_dict['name']] = tag_dict['default']
            # Update value from XML
            if self.configTS.xpath(tag_dict['tag'] + '/text()'):
                # If the variable should be a Boolean
                if tag_dict.get('type') == 'bool':
                    if self.configTS.xpath(tag_dict['tag'] + '/text()')[0].lower() == 'true':
                        value = True
                    else:
                        value = False
                # If the variable should be a Number
                elif tag_dict.get('type') == 'number':
                    value = self.configTS.xpath('round({})'.format(tag_dict['tag']))
                else:
                    value = self.configTS.xpath(tag_dict['tag'])[0].text
                self.project_globals[tag_dict['name']] = value

        return True