[Cluster-devel] conga/luci/site/luci/Extensions StorageReport. ...

rmccabe at sourceware.org rmccabe at sourceware.org
Mon Sep 24 19:48:34 UTC 2007


CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe at sourceware.org	2007-09-24 19:48:34

Modified files:
	luci/site/luci/Extensions: StorageReport.py storage_adapters.py 

Log message:
	Whitespace, readability cleanup

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/StorageReport.py.diff?cvsroot=cluster&r1=1.26&r2=1.27
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/storage_adapters.py.diff?cvsroot=cluster&r1=1.11&r2=1.12

--- conga/luci/site/luci/Extensions/StorageReport.py	2007/08/09 04:37:20	1.26
+++ conga/luci/site/luci/Extensions/StorageReport.py	2007/09/24 19:48:34	1.27
@@ -34,2066 +34,2061 @@
 
 from ricci_communicator import extract_module_status
 
-
 SESSION_STORAGE_XML_REPORT = 'storage_xml_report_dir'
 
-
 class StorageReport:
+	def __init__(self, storage_xml_report):
+		self.__report = storage_xml_report#.cloneNode(True)
 
-    def __init__(self, storage_xml_report):
-        self.__report = storage_xml_report#.cloneNode(True)
-
-        self.__mappers = None
-        self.__m_temps = None
-        for node in self.__report.childNodes:
-            try:
-                var = parse_variable(node)
-                if var.get_name() == 'mappers':
-                    self.__mappers = var.get_value()
-                if var.get_name() == 'mapper_templates':
-                    self.__m_temps = var.get_value()
-            except:
-                pass
-        if self.__mappers is None or self.__m_temps is None:
-            raise Exception, 'invalid storage_xml_report'
-
-        self.__mapp_dir = {} # holds mapper lists by mapper_type
-        for mapp_node in self.__mappers:
-            m_type = mapp_node.getAttribute('mapper_type')
-            if not (m_type in self.__mapp_dir):
-                self.__mapp_dir[m_type] = []
-            self.__mapp_dir[m_type].append(mapp_node)#.cloneNode(True))
-
-        self.__m_temps_dir = {} # holds mapper_template lists by mapper_type
-        for temp_node in self.__m_temps:
-            m_type = temp_node.getAttribute('mapper_type')
-            if not (m_type in self.__m_temps_dir):
-                self.__m_temps_dir[m_type] = []
-            self.__m_temps_dir[m_type].append(temp_node)#.cloneNode(True))
-        #
-
-
-
-
-
-    def get_xml_report(self):
-        return self.__report#.cloneNode(True)
-
-
-    def get_mappers(self, mapper_type=''):
-        l = []
-        if mapper_type == '':
-            l = self.__mappers
-        elif mapper_type in self.__mapp_dir:
-            l = self.__mapp_dir[mapper_type]
-        r = []
-        for s in l:
-            r.append(s)#s.cloneNode(True))
-        return r
-
-
-    def get_mappers_dir(self):
-        r = {}
-        for mapper_type in self.__mapp_dir:
-            l = []
-            for m in self.__mapp_dir[mapper_type]:
-                l.append(m)#.cloneNode(True))
-            r[mapper_type] = l
-        return r
-
-
-    def get_mapper(self, mapper_id):
-        if mapper_id == '':
-            raise Exception, 'empty mapper_id!!!'
-        for m in self.__mappers:
-            if m.getAttribute('mapper_id') == mapper_id:
-                return m#.cloneNode(True)
-        return None
-
-
-    def get_mapper_temps_dir(self):
-        r = {}
-        for mapper_type in self.__m_temps_dir:
-            l = []
-            for m in self.__m_temps_dir[mapper_type]:
-                l.append(m)#.cloneNode(True))
-            r[mapper_type] = l
-        return r
-
-
-    def get_mapper_temps(self, mapper_type=''):
-        l = []
-        if mapper_type == '':
-            l = self.__m_temps
-        elif mapper_type in self.__m_temps_dir:
-            l = self.__m_temps_dir[mapper_type]
-        r = []
-        for s in l:
-            r.append(s)#.cloneNode(True))
-        return r
-
-
-    def get_targets(self, mapper):
-        if mapper is None:
-            return []
-
-        targets_list = []
-        for node in mapper.childNodes:
-            if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                if node.nodeName == MAPPER_TARGETS_TAG:
-                    targets_xml = node
-                    for node in targets_xml.childNodes:
-                        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                            if node.nodeName == BD_TYPE:
-                                targets_list.append(node)#.cloneNode(True))
-        return targets_list
-
-
-    def get_new_targets(self, mapper):
-        if mapper is None:
-            return []
-
-        targets_list = []
-        for node in mapper.childNodes:
-            if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                if node.nodeName == MAPPER_NEW_TARGETS_TAG:
-                    targets_xml = node
-                    for node in targets_xml.childNodes:
-                        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                            if node.nodeName == BD_TEMPLATE:
-                                targets_list.append(node)#.cloneNode(True))
-        return targets_list
-
-
-    def get_sources(self, mapper):
-        if mapper is None:
-            return []
-
-        targets_list = []
-        for node in mapper.childNodes:
-            if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                if node.nodeName == MAPPER_SOURCES_TAG:
-                    targets_xml = node
-                    for node in targets_xml.childNodes:
-                        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                            if node.nodeName == BD_TYPE:
-                                targets_list.append(node)#.cloneNode(True))
-        return targets_list
-
-
-    def get_new_sources(self, mapper):
-        if mapper is None:
-            return []
-
-        targets_list = []
-        for node in mapper.childNodes:
-            if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                if node.nodeName == MAPPER_NEW_SOURCES_TAG:
-                    targets_xml = node
-                    for node in targets_xml.childNodes:
-                        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                            if node.nodeName == BD_TYPE:
-                                targets_list.append(node)#.cloneNode(True))
-        return targets_list
-
-
-    def get_mapper_props(self, mapper):
-        if mapper is None:
-            return None
-
-        props = None
-        for node in mapper.childNodes:
-            if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                if node.nodeName == PROPS_TAG:
-                    props = node#.cloneNode(True)
-        if props is None:
-            raise Exception, 'mapper missing properties tag'
-        return props
-
-
-    def get_target(self, mapper_id, path):
-        mapper = self.get_mapper(mapper_id)
-        if mapper is None:
-            return None
-
-        targets = self.get_targets(mapper)
-        for t_xml in targets:
-            if t_xml.getAttribute('path') == path:
-                return t_xml#.cloneNode(True)
-        return None
+		self.__mappers = None
+		self.__m_temps = None
+		for node in self.__report.childNodes:
+			try:
+				var = parse_variable(node)
+				if var.get_name() == 'mappers':
+					self.__mappers = var.get_value()
+				if var.get_name() == 'mapper_templates':
+					self.__m_temps = var.get_value()
+			except:
+				pass
+		if self.__mappers is None or self.__m_temps is None:
+			raise Exception, 'invalid storage_xml_report'
+
+		self.__mapp_dir = {} # holds mapper lists by mapper_type
+		for mapp_node in self.__mappers:
+			m_type = mapp_node.getAttribute('mapper_type')
+			if not (m_type in self.__mapp_dir):
+				self.__mapp_dir[m_type] = []
+			self.__mapp_dir[m_type].append(mapp_node)#.cloneNode(True))
+
+		self.__m_temps_dir = {} # holds mapper_template lists by mapper_type
+		for temp_node in self.__m_temps:
+			m_type = temp_node.getAttribute('mapper_type')
+			if not (m_type in self.__m_temps_dir):
+				self.__m_temps_dir[m_type] = []
+			self.__m_temps_dir[m_type].append(temp_node)#.cloneNode(True))
+		#
+
+	def get_xml_report(self):
+		return self.__report#.cloneNode(True)
+
+	def get_mappers(self, mapper_type=''):
+		l = []
+		if mapper_type == '':
+			l = self.__mappers
+		elif mapper_type in self.__mapp_dir:
+			l = self.__mapp_dir[mapper_type]
+		r = []
+		for s in l:
+			r.append(s)#s.cloneNode(True))
+		return r
+
+	def get_mappers_dir(self):
+		r = {}
+		for mapper_type in self.__mapp_dir:
+			l = []
+			for m in self.__mapp_dir[mapper_type]:
+				l.append(m)#.cloneNode(True))
+			r[mapper_type] = l
+		return r
+
+	def get_mapper(self, mapper_id):
+		if mapper_id == '':
+			raise Exception, 'empty mapper_id!!!'
+		for m in self.__mappers:
+			if m.getAttribute('mapper_id') == mapper_id:
+				return m#.cloneNode(True)
+		return None
+
+	def get_mapper_temps_dir(self):
+		r = {}
+		for mapper_type in self.__m_temps_dir:
+			l = []
+			for m in self.__m_temps_dir[mapper_type]:
+				l.append(m)#.cloneNode(True))
+			r[mapper_type] = l
+		return r
+
+	def get_mapper_temps(self, mapper_type=''):
+		l = []
+		if mapper_type == '':
+			l = self.__m_temps
+		elif mapper_type in self.__m_temps_dir:
+			l = self.__m_temps_dir[mapper_type]
+		r = []
+		for s in l:
+			r.append(s)#.cloneNode(True))
+		return r
+
+	def get_targets(self, mapper):
+		if mapper is None:
+			return []
+
+		targets_list = []
+		for node in mapper.childNodes:
+			if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+				if node.nodeName == MAPPER_TARGETS_TAG:
+					targets_xml = node
+					for node in targets_xml.childNodes:
+						if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+							if node.nodeName == BD_TYPE:
+								targets_list.append(node)#.cloneNode(True))
+		return targets_list
+
+	def get_new_targets(self, mapper):
+		if mapper is None:
+			return []
+
+		targets_list = []
+		for node in mapper.childNodes:
+			if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+				if node.nodeName == MAPPER_NEW_TARGETS_TAG:
+					targets_xml = node
+					for node in targets_xml.childNodes:
+						if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+							if node.nodeName == BD_TEMPLATE:
+								targets_list.append(node)#.cloneNode(True))
+		return targets_list
+
+	def get_sources(self, mapper):
+		if mapper is None:
+			return []
+
+		targets_list = []
+		for node in mapper.childNodes:
+			if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+				if node.nodeName == MAPPER_SOURCES_TAG:
+					targets_xml = node
+					for node in targets_xml.childNodes:
+						if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+							if node.nodeName == BD_TYPE:
+								targets_list.append(node)#.cloneNode(True))
+		return targets_list
+
+	def get_new_sources(self, mapper):
+		if mapper is None:
+			return []
+
+		targets_list = []
+		for node in mapper.childNodes:
+			if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+				if node.nodeName == MAPPER_NEW_SOURCES_TAG:
+					targets_xml = node
+					for node in targets_xml.childNodes:
+						if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+							if node.nodeName == BD_TYPE:
+								targets_list.append(node)#.cloneNode(True))
+		return targets_list
+
+	def get_mapper_props(self, mapper):
+		if mapper is None:
+			return None
+
+		props = None
+		for node in mapper.childNodes:
+			if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+				if node.nodeName == PROPS_TAG:
+					props = node#.cloneNode(True)
+		if props is None:
+			raise Exception, 'mapper missing properties tag'
+		return props
+
+	def get_target(self, mapper_id, path):
+		mapper = self.get_mapper(mapper_id)
+		if mapper is None:
+			return None
+
+		targets = self.get_targets(mapper)
+		for t_xml in targets:
+			if t_xml.getAttribute('path') == path:
+				return t_xml#.cloneNode(True)
+		return None
 
 def is_storage_report_cached(session, storagename):
-    if session.has_key(SESSION_STORAGE_XML_REPORT):
-        reports_dir = session[SESSION_STORAGE_XML_REPORT]
-        if reports_dir.has_key(storagename):
-            if reports_dir[storagename] is not None:
-                return True
-    return False
+	if session.has_key(SESSION_STORAGE_XML_REPORT):
+		reports_dir = session[SESSION_STORAGE_XML_REPORT]
+		if reports_dir.has_key(storagename):
+			if reports_dir[storagename] is not None:
+				return True
+	return False
 
 def invalidate_storage_report(session, storagename):
-    reports_dir = {}
-    if session.has_key(SESSION_STORAGE_XML_REPORT):
-        reports_dir = session[SESSION_STORAGE_XML_REPORT]
-    reports_dir[storagename] = None
-    session.set(SESSION_STORAGE_XML_REPORT, reports_dir)
-    return
+	reports_dir = {}
+	if session.has_key(SESSION_STORAGE_XML_REPORT):
+		reports_dir = session[SESSION_STORAGE_XML_REPORT]
+	reports_dir[storagename] = None
+	session.set(SESSION_STORAGE_XML_REPORT, reports_dir)
+	return
 
 def cache_storage_report(ricci_comm, session):
-    try:
-        rep = get_storage_report(ricci_comm, session)
-        if rep is None:
-            raise Exception, 'Unable to communicate with host (either system down or ricci not running on it)'
-        else:
-            return True
-    except Exception, e:
-        return str(e)
-    except:
-        return 'Luci internal error. Please file bug report.'
-    return 'should never come here'
+	try:
+		rep = get_storage_report(ricci_comm, session)
+		if rep is None:
+			raise Exception, 'Unable to communicate with host (either system down or ricci not running on it)'
+		else:
+			return True
+	except Exception, e:
+		return str(e)
+	except:
+		return 'Luci internal error. Please file bug report.'
+	return 'should never come here'
 
 def get_storage_report(ricci_comm, session):
-    if ricci_comm is None:
-        return None
+	if ricci_comm is None:
+		return None
 
-    storagename = ricci_comm.hostname()
+	storagename = ricci_comm.hostname()
 
-    # setup cache, if not already set up
-    if not session.has_key(SESSION_STORAGE_XML_REPORT):
-        session.set(SESSION_STORAGE_XML_REPORT, {})
-    # return cached report if existing
-    if session[SESSION_STORAGE_XML_REPORT].has_key(storagename):
-        tmp_report = session[SESSION_STORAGE_XML_REPORT][storagename]
-        if tmp_report is not None:
-            return StorageReport(tmp_report)
-
-
-    # request
-    doc = minidom.Document()
-    batch = doc.createElement('batch')
-    module = doc.createElement('module')
-    module.setAttribute('name', 'storage')
-    request = doc.createElement('request')
-    request.setAttribute('API_version', '1.0')
-    function = doc.createElement('function_call')
-    function.setAttribute('name', 'report')
-    batch.appendChild(module)
-    module.appendChild(request)
-    request.appendChild(function)
-
-    # get report
-    batch_r = ricci_comm.process_batch(batch)
-    if batch_r.getAttribute('status') != '0':
-        #raise Exception, 'error retrieving storage report'
-        # dig deeper to find causing error
-        pass
-    module_r = None
-    for node in batch_r.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == 'module':
-                module_r = node
-    if module_r is None:
-        raise Exception, 'malformed response: missing <module/> in <batch/>'
-    module_r_status = module_r.getAttribute('status')
-    if module_r_status != '0':
-        #raise Exception, 'error retrieving storage report'
-        if module_r_status == '3':
-            raise Exception, 'Unable to find storage module on host (reinstall it)'
-    resp_r = None
-    for node in module_r.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == 'response':
-                resp_r = node
-    if resp_r is None:
-        raise Exception, 'malformed response: missing <response/> in <module/>'
-    fr_r = None
-    for node in resp_r.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == 'function_response':
-                fr_r = node
-    if fr_r is None:
-        raise Exception, 'malformed response: missing <function_response/> in <response/>'
-    succ_v     = None
-    err_code_v = None
-    err_desc_v = None
-    for node in fr_r.childNodes:
-        try:
-            var = parse_variable(node)
-            if var.get_name() == 'success':
-                succ_v = var
-            elif var.get_name() == 'error_code':
-                err_code_v = var
-            elif var.get_name() == 'error_description':
-                err_desc_v = var
-        except:
-            pass
-    if succ_v is None:
-        raise Exception, 'malformed response: missing "success" variable in <function_response/>'
-    if succ_v.get_value() is not True:
-        # error
-        if err_code_v.get_value() == -1:
-            raise Exception, 'Generic error on host:\n\n%s' % err_desc_v.get_value()
-        else:
-            raise Exception, 'Host responded: %s' % err_desc_v.get_value()
-
-    xml_report = fr_r
-
-    # cache xml_report
-    reports_dir = session[SESSION_STORAGE_XML_REPORT]
-    reports_dir[storagename] = xml_report
-    session.set(SESSION_STORAGE_XML_REPORT, reports_dir)
+	# setup cache, if not already set up
+	if not session.has_key(SESSION_STORAGE_XML_REPORT):
+		session.set(SESSION_STORAGE_XML_REPORT, {})
+	# return cached report if existing
+	if session[SESSION_STORAGE_XML_REPORT].has_key(storagename):
+		tmp_report = session[SESSION_STORAGE_XML_REPORT][storagename]
+		if tmp_report is not None:
+			return StorageReport(tmp_report)
+
+	# request
+	doc = minidom.Document()
+	batch = doc.createElement('batch')
+	module = doc.createElement('module')
+	module.setAttribute('name', 'storage')
+	request = doc.createElement('request')
+	request.setAttribute('API_version', '1.0')
+	function = doc.createElement('function_call')
+	function.setAttribute('name', 'report')
+	batch.appendChild(module)
+	module.appendChild(request)
+	request.appendChild(function)
+
+	# get report
+	batch_r = ricci_comm.process_batch(batch)
+	if batch_r.getAttribute('status') != '0':
+		#raise Exception, 'error retrieving storage report'
+		# dig deeper to find causing error
+		pass
+	module_r = None
+	for node in batch_r.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == 'module':
+				module_r = node
+	if module_r is None:
+		raise Exception, 'malformed response: missing <module/> in <batch/>'
+	module_r_status = module_r.getAttribute('status')
+	if module_r_status != '0':
+		#raise Exception, 'error retrieving storage report'
+		if module_r_status == '3':
+			raise Exception, 'Unable to find storage module on host (reinstall it)'
+	resp_r = None
+	for node in module_r.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == 'response':
+				resp_r = node
+	if resp_r is None:
+		raise Exception, 'malformed response: missing <response/> in <module/>'
+	fr_r = None
+	for node in resp_r.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == 'function_response':
+				fr_r = node
+	if fr_r is None:
+		raise Exception, 'malformed response: missing <function_response/> in <response/>'
+	succ_v = None
+	err_code_v = None
+	err_desc_v = None
+	for node in fr_r.childNodes:
+		try:
+			var = parse_variable(node)
+			if var.get_name() == 'success':
+				succ_v = var
+			elif var.get_name() == 'error_code':
+				err_code_v = var
+			elif var.get_name() == 'error_description':
+				err_desc_v = var
+		except:
+			pass
+	if succ_v is None:
+		raise Exception, 'malformed response: missing "success" variable in <function_response/>'
+	if succ_v.get_value() is not True:
+		# error
+		if err_code_v.get_value() == -1:
+			raise Exception, 'Generic error on host:\n\n%s' % err_desc_v.get_value()
+		else:
+			raise Exception, 'Host responded: %s' % err_desc_v.get_value()
+
+	xml_report = fr_r
+
+	# cache xml_report
+	reports_dir = session[SESSION_STORAGE_XML_REPORT]
+	reports_dir[storagename] = xml_report
+	session.set(SESSION_STORAGE_XML_REPORT, reports_dir)
 
-    return StorageReport(xml_report)
+	return StorageReport(xml_report)
 
 
 def get_content_data(self, storage_report, mapper_id, bd_path, content_id):
-    bd_data = get_bd_data(self, storage_report, mapper_id, bd_path)
-    for cont in bd_data['contents']:
-        if cont['id'] == content_id:
-            return cont
-    return None
+	bd_data = get_bd_data(self, storage_report, mapper_id, bd_path)
+	for cont in bd_data['contents']:
+		if cont['id'] == content_id:
+			return cont
+	return None
 
 def get_bd_data(self, storage_report, mapper_id, path):
-    if storage_report is None or mapper_id is None:
-        return None
+	if storage_report is None or mapper_id is None:
+		return None
 
-    mapper = get_mapper_data(self, storage_report, mapper_id)
-    if mapper is None:
-        return None
-
-    for t in mapper['targets']:
-        if t['path'] == path:
-            return t
-    for t in mapper['new_targets']:
-        if t['path'] == path:
-            return t
-    if path == 'new_snapshot' and mapper['mapper_type'] == MAPPER_VG_TYPE:
-        return mapper['snapshot_template']
-    return None
+	mapper = get_mapper_data(self, storage_report, mapper_id)
+	if mapper is None:
+		return None
+
+	for t in mapper['targets']:
+		if t['path'] == path:
+			return t
+	for t in mapper['new_targets']:
+		if t['path'] == path:
+			return t
+	if path == 'new_snapshot' and mapper['mapper_type'] == MAPPER_VG_TYPE:
+		return mapper['snapshot_template']
+	return None
 
 def get_mappers_data(self, storage_report):
-    ret_dir = {}
-    # mappers
-    mappers_dir = storage_report.get_mappers_dir()
-    for mapp_type in mappers_dir:
-        for m_xml in mappers_dir[mapp_type]:
-            mapper_id = m_xml.getAttribute('mapper_id')
-            if mapp_type not in ret_dir:
-                ret_dir[mapp_type] = {}
-                ret_dir[mapp_type]['mappers'] = []
-                ret_dir[mapp_type]['mapper_template'] = None
-            ret_dir[mapp_type]['mappers'].append(get_mapper_data(self, storage_report, mapper_id))
-    # templates
-    for mapp_type in storage_report.get_mapper_temps_dir():
-        if mapp_type not in ret_dir:
-            ret_dir[mapp_type] = {}
-            ret_dir[mapp_type]['mappers'] = []
-        ret_dir[mapp_type]['mapper_template'] = get_mapper_template_data(self, storage_report, mapp_type)
-
-    # pretty stuff
-    for mapp_type in ret_dir:
-        info = ret_dir[mapp_type]
-        info_source = None
-        if len(info['mappers']) != 0:
-            info_source = info['mappers'][0]
-        else:
-            info_source = info['mapper_template']
-        info['pretty_type'] = info_source['pretty_type']
-        info['pretty_target_name'] = info_source['pretty_target_name']
-        info['pretty_targets_name'] = info_source['pretty_targets_name']
-        info['pretty_source_name'] = info_source['pretty_source_name']
-        info['pretty_sources_name'] = info_source['pretty_sources_name']
+	ret_dir = {}
+	# mappers
+	mappers_dir = storage_report.get_mappers_dir()
+	for mapp_type in mappers_dir:
+		for m_xml in mappers_dir[mapp_type]:
+			mapper_id = m_xml.getAttribute('mapper_id')
+			if mapp_type not in ret_dir:
+				ret_dir[mapp_type] = {}
+				ret_dir[mapp_type]['mappers'] = []
+				ret_dir[mapp_type]['mapper_template'] = None
+			ret_dir[mapp_type]['mappers'].append(get_mapper_data(self, storage_report, mapper_id))
+	# templates
+	for mapp_type in storage_report.get_mapper_temps_dir():
+		if mapp_type not in ret_dir:
+			ret_dir[mapp_type] = {}
+			ret_dir[mapp_type]['mappers'] = []
+		ret_dir[mapp_type]['mapper_template'] = get_mapper_template_data(self, storage_report, mapp_type)
+
+	# pretty stuff
+	for mapp_type in ret_dir:
+		info = ret_dir[mapp_type]
+		info_source = None
+		if len(info['mappers']) != 0:
+			info_source = info['mappers'][0]
+		else:
+			info_source = info['mapper_template']
+		info['pretty_type'] = info_source['pretty_type']
+		info['pretty_target_name'] = info_source['pretty_target_name']
+		info['pretty_targets_name'] = info_source['pretty_targets_name']
+		info['pretty_source_name'] = info_source['pretty_source_name']
+		info['pretty_sources_name'] = info_source['pretty_sources_name']
 
-    return ret_dir
+	return ret_dir
 
 def get_mapper_data(self, storage_report, mapper_id):
-    if self is None or storage_report is None or mapper_id is None:
-        return None
-
-    session = self.REQUEST.SESSION
+	if self is None or storage_report is None or mapper_id is None:
+		return None
 
-    mapper = storage_report.get_mapper(mapper_id)
-    if mapper is None:
-        return None
-
-    removable, props = get_props_data_internal(session, mapper)
-
-    new_targets = []
-    for t_xml in storage_report.get_new_targets(mapper):
-        new_targets.append(get_bd_data_internal(session, t_xml, mapper))
-    new_sources = []
-    for s_xml in storage_report.get_new_sources(mapper):
-        new_sources.append(get_bd_data_internal(session, s_xml, mapper))
-    targets = []
-    for t_xml in storage_report.get_targets(mapper):
-        targets.append(get_bd_data_internal(session, t_xml, mapper))
-    sources = []
-    for s_xml in storage_report.get_sources(mapper):
-        sources.append(get_bd_data_internal(session, s_xml, mapper))
-
-    mapper_type = mapper.getAttribute('mapper_type')
-    pretty_type, pretty_target_name, pretty_source_name = get_pretty_mapper_info(mapper_type)
-    pretty_name = mapper_id.replace('%s:' % mapper_type, '').replace('/dev/', '')
-    pretty_targets_name = '%ss' % pretty_target_name
-    pretty_sources_name = '%ss' % pretty_source_name
-    icon_name, dummy1, dummy2 = get_mapper_icons(mapper_type)
-    color = 'black'
-
-    mapper_ret = {}
-    mapper_ret['pretty_type'] = pretty_type
-    mapper_ret['pretty_name'] = pretty_name
-    mapper_ret['pretty_target_name'] = pretty_target_name
-    mapper_ret['pretty_targets_name'] = pretty_targets_name
-    mapper_ret['pretty_source_name'] = pretty_source_name
-    mapper_ret['pretty_sources_name'] = pretty_sources_name
-    mapper_ret['mapper_id'] = mapper_id
-    mapper_ret['mapper_type'] = mapper_type
-    mapper_ret['props'] = props
-    mapper_ret['props_ordered'] = get_ordered_props(props)
-    mapper_ret['targets'] = targets
-    mapper_ret['new_targets'] = new_targets
-    mapper_ret['sources'] = sources
-    mapper_ret['new_sources'] = new_sources
-    mapper_ret['icon'] = icon_name
-    mapper_ret['color'] = color
-    mapper_ret['xml'] = mapper#.cloneNode(True)
-
-    assemble_all_targets(mapper_ret)
-
-    actions = []
-    if removable:
-        action = {'name' : 'Remove',
-                  'msg'  : 'Are you sure you want to remove %s \\\'%s\\\'?' % (pretty_type, pretty_name),
-                  'link' : ''}
-        actions.append(action)
-    if mapper_type == MAPPER_VG_TYPE or mapper_type == MAPPER_MDRAID_TYPE or mapper_type == MAPPER_ATARAID_TYPE or mapper_type == MAPPER_MULTIPATH_TYPE:
-        action = {'name' : 'Add %s' % mapper_ret['pretty_sources_name'],
-                  'msg'  : '',
-                  'link' : './?%s=%s&%s=%s&%s=%s' % (PAGETYPE, ADD_SOURCES, PT_MAPPER_ID, mapper_ret['mapper_id'], PT_MAPPER_TYPE, mapper_ret['mapper_type'])}
-        actions.append(action)
-    if mapper_type == MAPPER_VG_TYPE:
-        for nt in mapper_ret['new_targets']:
-            if nt['props']['snapshot']['value'] == 'false':
-                if nt['new']:
-                    action = {'name' : 'New %s' % mapper_ret['pretty_target_name'],
-                              'msg'  : '',
-                              'link' : './?%s=%s&%s=%s&%s=%s&%s=%s' \
-                                 % (PAGETYPE, VIEW_BD,
-                                    PT_MAPPER_ID, mapper_ret['mapper_id'], \
-                                    PT_MAPPER_TYPE, mapper_ret['mapper_type'], \
-                                    PT_PATH, nt['path'])}
-                    actions.append(action)
-                    break
-    mapper_ret['actions'] = actions
-
-    if mapper_type == MAPPER_VG_TYPE:
-        link_snapshots(mapper_ret)
-
-    # cylinders work properly for VGs only, for now
-    mapper_ret['graphical_view'] = mapper_type != MAPPER_PT_TYPE
-    if mapper_ret['graphical_view']:
-        mapper_ret['mappings-view_css_classnames'] = {'graphical_view' : 'visible',
-                                                      'textual_view'   : 'invisible'}
-    else:
-        mapper_ret['mappings-view_css_classnames'] = {'graphical_view' : 'invisible',
-                                                      'textual_view'   : 'visible'}
+	session = self.REQUEST.SESSION
 
-    mapper_ret['need_apply_button'] = mutable_props(mapper_ret['props'])
-
-    return mapper_ret
+	mapper = storage_report.get_mapper(mapper_id)
+	if mapper is None:
+		return None
+
+	removable, props = get_props_data_internal(session, mapper)
+
+	new_targets = []
+	for t_xml in storage_report.get_new_targets(mapper):
+		new_targets.append(get_bd_data_internal(session, t_xml, mapper))
+
+	new_sources = []
+	for s_xml in storage_report.get_new_sources(mapper):
+		new_sources.append(get_bd_data_internal(session, s_xml, mapper))
+
+	targets = []
+	for t_xml in storage_report.get_targets(mapper):
+		targets.append(get_bd_data_internal(session, t_xml, mapper))
+
+	sources = []
+	for s_xml in storage_report.get_sources(mapper):
+		sources.append(get_bd_data_internal(session, s_xml, mapper))
+
+	mapper_type = mapper.getAttribute('mapper_type')
+	pretty_type, pretty_target_name, pretty_source_name = get_pretty_mapper_info(mapper_type)
+	pretty_name = mapper_id.replace('%s:' % mapper_type, '').replace('/dev/', '')
+	pretty_targets_name = '%ss' % pretty_target_name
+	pretty_sources_name = '%ss' % pretty_source_name
+	icon_name, dummy1, dummy2 = get_mapper_icons(mapper_type)
+	color = 'black'
+
+	mapper_ret = {}
+	mapper_ret['pretty_type'] = pretty_type
+	mapper_ret['pretty_name'] = pretty_name
+	mapper_ret['pretty_target_name'] = pretty_target_name
+	mapper_ret['pretty_targets_name'] = pretty_targets_name
+	mapper_ret['pretty_source_name'] = pretty_source_name
+	mapper_ret['pretty_sources_name'] = pretty_sources_name
+	mapper_ret['mapper_id'] = mapper_id
+	mapper_ret['mapper_type'] = mapper_type
+	mapper_ret['props'] = props
+	mapper_ret['props_ordered'] = get_ordered_props(props)
+	mapper_ret['targets'] = targets
+	mapper_ret['new_targets'] = new_targets
+	mapper_ret['sources'] = sources
+	mapper_ret['new_sources'] = new_sources
+	mapper_ret['icon'] = icon_name
+	mapper_ret['color'] = color
+	mapper_ret['xml'] = mapper#.cloneNode(True)
+
+	assemble_all_targets(mapper_ret)
+
+	actions = []
+	if removable:
+		action = {
+			'name': 'Remove',
+			'msg': 'Are you sure you want to remove %s \\\'%s\\\'?' % (pretty_type, pretty_name),
+			'link': ''
+		}
+		actions.append(action)
+	if mapper_type == MAPPER_VG_TYPE or mapper_type == MAPPER_MDRAID_TYPE or mapper_type == MAPPER_ATARAID_TYPE or mapper_type == MAPPER_MULTIPATH_TYPE:
+		action = {
+			'name': 'Add %s' % mapper_ret['pretty_sources_name'],
+			'msg': '',
+			'link': './?%s=%s&%s=%s&%s=%s' \
+				% (PAGETYPE, ADD_SOURCES, PT_MAPPER_ID, mapper_ret['mapper_id'], PT_MAPPER_TYPE, mapper_ret['mapper_type'])
+		}
+		actions.append(action)
+	if mapper_type == MAPPER_VG_TYPE:
+		for nt in mapper_ret['new_targets']:
+			if nt['props']['snapshot']['value'] == 'false':
+				if nt['new']:
+					action = {
+						'name': 'New %s' % mapper_ret['pretty_target_name'],
+						'msg': '',
+						'link': './?%s=%s&%s=%s&%s=%s&%s=%s' \
+							% (PAGETYPE, VIEW_BD,
+								PT_MAPPER_ID, mapper_ret['mapper_id'], \
+								PT_MAPPER_TYPE, mapper_ret['mapper_type'], \
+								PT_PATH, nt['path'])
+					}
+					actions.append(action)
+					break
+	mapper_ret['actions'] = actions
+
+	if mapper_type == MAPPER_VG_TYPE:
+		link_snapshots(mapper_ret)
+
+	# cylinders work properly for VGs only, for now
+	mapper_ret['graphical_view'] = mapper_type != MAPPER_PT_TYPE
+	if mapper_ret['graphical_view']:
+		mapper_ret['mappings-view_css_classnames'] = {
+			'graphical_view': 'visible',
+			'textual_view': 'invisible'
+		}
+	else:
+		mapper_ret['mappings-view_css_classnames'] = {
+			'graphical_view': 'invisible',
+			'textual_view': 'visible'
+		}
 
+	mapper_ret['need_apply_button'] = mutable_props(mapper_ret['props'])
+	return mapper_ret
 
 def link_snapshots(mapper):
-    for snap in mapper['targets']:
-        if snap['props']['snapshot']['value'] != 'true':
-            continue
-        orig_name = snap['props']['snapshot_origin']['value']
-        snap['description'] = '%s, %s\'s Snapshot' \
-            % (snap['description'], orig_name)
-
-        # find origin
-        for t in mapper['targets']:
-            if t['pretty_name'] == orig_name:
-                if 'snapshots' not in t:
-                    t['snapshots'] = []
-                snap['origin'] = t
-                t['snapshots'].append(snap)
-    return
-
-
+	for snap in mapper['targets']:
+		if snap['props']['snapshot']['value'] != 'true':
+			continue
+		orig_name = snap['props']['snapshot_origin']['value']
+		snap['description'] = '%s, %s\'s Snapshot' \
+			% (snap['description'], orig_name)
+
+		# find origin
+		for t in mapper['targets']:
+			if t['pretty_name'] == orig_name:
+				if 'snapshots' not in t:
+					t['snapshots'] = []
+				snap['origin'] = t
+				t['snapshots'].append(snap)
+	return
 
 def assemble_all_targets(mapper_data):
-    mdata = mapper_data
-    targets_all = []
+	mdata = mapper_data
+	targets_all = []
 
-    if mdata['mapper_type'] == MAPPER_VG_TYPE:
-        for t in mdata['targets']:
-            targets_all.append(t)
-        for t in mdata['new_targets']:
-            if t['props']['snapshot']['value'] == 'false':
-                targets_all.append(t)
-            else:
-                mdata['snapshot_template'] = t
-    elif mdata['mapper_type'] == MAPPER_PT_TYPE:
-        # extended-primary substitution
-        extended_templs = []
-        for t in mdata['new_targets']:
-            if t['props']['partition_type']['value'] == 'extended':
-                extended_templs.append(t)
-        for ext in extended_templs:
-            # find matching primary parts
-            for t in mdata['new_targets']:
-                if t['props']['partition_type']['value'] == 'primary':
-                    if t['props']['partition_begin']['value'] == ext['props']['partition_begin']['value']:
-                        t['props']['partition_type']['replacements'] = {'repl_names' : ['primary', 'extended'],
-                                                                        'primary' : t,
-                                                                        'extended' : ext }
-                        ext['props']['partition_type']['replacements'] = {'repl_names' : ['extended', 'primary'],
-                                                                          'extended' : ext,
-                                                                          'primary' : t }
-        for t in mdata['targets']:
-            targets_all.append(t)
-        for t in mdata['new_targets']:
-            if t['props']['partition_type']['value'] != 'extended':
-                targets_all.append(t)
-
-        # TODO: place logical into extended
-
-        # sort partitions
-        p_sorted = []
-        while len(targets_all) != 0:
-            smallest_num = 100000000000000000000
-            smallest_bd = None
-            smallest_index = 0
-            i = 0
-            for i in xrange(len(targets_all)):
-                bd = targets_all[i]
-                begin = int(bd['props']['partition_begin']['value'])
-                if begin < smallest_num:
-                    smallest_num = begin
-                    smallest_bd = bd
-                    smallest_index = i
-            targets_all.pop(smallest_index)
-            p_sorted.append(smallest_bd)
-        targets_all = p_sorted
-    else:
-        for t in mdata['targets']:
-            targets_all.append(t)
-        for t in mdata['new_targets']:
-            targets_all.append(t)
+	if mdata['mapper_type'] == MAPPER_VG_TYPE:
+		for t in mdata['targets']:
+			targets_all.append(t)
+		for t in mdata['new_targets']:
+			if t['props']['snapshot']['value'] == 'false':
+				targets_all.append(t)
+			else:
+				mdata['snapshot_template'] = t
+	elif mdata['mapper_type'] == MAPPER_PT_TYPE:
+		# extended-primary substitution
+		extended_templs = []
+		for t in mdata['new_targets']:
+			if t['props']['partition_type']['value'] == 'extended':
+				extended_templs.append(t)
+		for ext in extended_templs:
+			# find matching primary parts
+			for t in mdata['new_targets']:
+				if t['props']['partition_type']['value'] == 'primary':
+					if t['props']['partition_begin']['value'] == ext['props']['partition_begin']['value']:
+						t['props']['partition_type']['replacements'] = {
+							'repl_names': ['primary', 'extended'],
+							'primary': t,
+							'extended': ext
+						}
+
+						ext['props']['partition_type']['replacements'] = {
+							'repl_names': ['extended', 'primary'],
+							'extended': ext,
+							'primary': t
+						}
+		for t in mdata['targets']:
+			targets_all.append(t)
+		for t in mdata['new_targets']:
+			if t['props']['partition_type']['value'] != 'extended':
+				targets_all.append(t)
+
+		# TODO: place logical into extended
+
+		# sort partitions
+		p_sorted = []
+		while len(targets_all) != 0:
+			smallest_num = 100000000000000000000
+			smallest_bd = None
+			smallest_index = 0
+			i = 0
+			for i in xrange(len(targets_all)):
+				bd = targets_all[i]
+				begin = int(bd['props']['partition_begin']['value'])
+				if begin < smallest_num:
+					smallest_num = begin
+					smallest_bd = bd
+					smallest_index = i
+			targets_all.pop(smallest_index)
+			p_sorted.append(smallest_bd)
+		targets_all = p_sorted
+	else:
+		for t in mdata['targets']:
+			targets_all.append(t)
+		for t in mdata['new_targets']:
+			targets_all.append(t)
 
-    mdata['targets_all'] = targets_all
+	mdata['targets_all'] = targets_all
 
 def get_mapper_template_data(self, storage_report, mapper_type):
-    if self is None or storage_report is None or mapper_type is None:
-        return None
-
-    session = self.REQUEST.SESSION
-
-    mapper_id = ''
-
-    templ_xml_list = storage_report.get_mapper_temps(mapper_type)
-    mapper = None
-    if len(templ_xml_list) != 0:
-        mapper = templ_xml_list[0]
-    if mapper is None:
-        return None
-
-    removable, props = get_props_data_internal(session, mapper)
-
-    new_targets = []
-    for t_xml in storage_report.get_new_targets(mapper):
-        new_targets.append(get_bd_data_internal(session, t_xml, mapper))
-    new_sources = []
-    for s_xml in storage_report.get_new_sources(mapper):
-        new_sources.append(get_bd_data_internal(session, s_xml, mapper))
-    targets = []
-    for t_xml in storage_report.get_targets(mapper):
-        targets.append(get_bd_data_internal(session, t_xml, mapper))
-    sources = []
-    for s_xml in storage_report.get_sources(mapper):
-        sources.append(get_bd_data_internal(session, s_xml, mapper))
-
-    mapper_type = mapper.getAttribute('mapper_type')
-    pretty_type, pretty_target_name, pretty_source_name = get_pretty_mapper_info(mapper_type)
-    pretty_name = mapper_id.replace('%s:' % mapper_type, '').replace('/dev/', '')
-    pretty_targets_name = '%ss' % pretty_target_name
-    pretty_sources_name = '%ss' % pretty_source_name
-    icon_name, dummy1, dummy2 = get_mapper_icons(mapper_type)
-    color = 'black'
-
-    min_sources = '0'
-    max_sources = '0'
-    new_props = {}
-    for name in props:
-        if name == 'min_sources':
-            min_sources = props[name]['value']
-        elif name == 'max_sources':
-            max_sources = props[name]['value']
-        else:
-            new_props[name] = props[name]
-    props = new_props
-
-    mapper_ret = {}
-    mapper_ret['pretty_type'] = pretty_type
-    mapper_ret['pretty_name'] = pretty_name
-    mapper_ret['pretty_target_name'] = pretty_target_name
-    mapper_ret['pretty_targets_name'] = pretty_targets_name
-    mapper_ret['pretty_source_name'] = pretty_source_name
-    mapper_ret['pretty_sources_name'] = pretty_sources_name
-    mapper_ret['mapper_id'] = mapper_id
-    mapper_ret['mapper_type'] = mapper_type
-    mapper_ret['props'] = props
-    mapper_ret['props_ordered'] = get_ordered_props(props)
-    #mapper_ret['removable'] = removable
-    mapper_ret['targets'] = targets
-    mapper_ret['new_targets'] = new_targets
-    mapper_ret['sources'] = sources
-    mapper_ret['new_sources'] = new_sources
-    mapper_ret['min_sources'] = min_sources
-    mapper_ret['max_sources'] = max_sources
-    mapper_ret['icon'] = icon_name
-    mapper_ret['color'] = color
-    mapper_ret['xml'] = mapper#.cloneNode(True)
-
-    mapper_ret['actions'] = []
-
-    mapper_ret['need_apply_button'] = True
-
-    return mapper_ret
-
-
+	if self is None or storage_report is None or mapper_type is None:
+		return None
 
+	session = self.REQUEST.SESSION
 
+	mapper_id = ''
 
+	templ_xml_list = storage_report.get_mapper_temps(mapper_type)
+	mapper = None
+
+	if len(templ_xml_list) != 0:
+		mapper = templ_xml_list[0]
+
+	if mapper is None:
+		return None
+
+	removable, props = get_props_data_internal(session, mapper)
+
+	new_targets = []
+	for t_xml in storage_report.get_new_targets(mapper):
+		new_targets.append(get_bd_data_internal(session, t_xml, mapper))
+
+	new_sources = []
+	for s_xml in storage_report.get_new_sources(mapper):
+		new_sources.append(get_bd_data_internal(session, s_xml, mapper))
+
+	targets = []
+	for t_xml in storage_report.get_targets(mapper):
+		targets.append(get_bd_data_internal(session, t_xml, mapper))
+
+	sources = []
+	for s_xml in storage_report.get_sources(mapper):
+		sources.append(get_bd_data_internal(session, s_xml, mapper))
+
+	mapper_type = mapper.getAttribute('mapper_type')
+	pretty_type, pretty_target_name, pretty_source_name = get_pretty_mapper_info(mapper_type)
+	pretty_name = mapper_id.replace('%s:' % mapper_type, '').replace('/dev/', '')
+	pretty_targets_name = '%ss' % pretty_target_name
+	pretty_sources_name = '%ss' % pretty_source_name
+	icon_name, dummy1, dummy2 = get_mapper_icons(mapper_type)
+	color = 'black'
+
+	min_sources = '0'
+	max_sources = '0'
+	new_props = {}
+	for name in props:
+		if name == 'min_sources':
+			min_sources = props[name]['value']
+		elif name == 'max_sources':
+			max_sources = props[name]['value']
+		else:
+			new_props[name] = props[name]
+	props = new_props
+
+	mapper_ret = {}
+	mapper_ret['pretty_type'] = pretty_type
+	mapper_ret['pretty_name'] = pretty_name
+	mapper_ret['pretty_target_name'] = pretty_target_name
+	mapper_ret['pretty_targets_name'] = pretty_targets_name
+	mapper_ret['pretty_source_name'] = pretty_source_name
+	mapper_ret['pretty_sources_name'] = pretty_sources_name
+	mapper_ret['mapper_id'] = mapper_id
+	mapper_ret['mapper_type'] = mapper_type
+	mapper_ret['props'] = props
+	mapper_ret['props_ordered'] = get_ordered_props(props)
+	#mapper_ret['removable'] = removable
+	mapper_ret['targets'] = targets
+	mapper_ret['new_targets'] = new_targets
+	mapper_ret['sources'] = sources
+	mapper_ret['new_sources'] = new_sources
+	mapper_ret['min_sources'] = min_sources
+	mapper_ret['max_sources'] = max_sources
+	mapper_ret['icon'] = icon_name
+	mapper_ret['color'] = color
+	mapper_ret['xml'] = mapper#.cloneNode(True)
+
+	mapper_ret['actions'] = []
+	mapper_ret['need_apply_button'] = True
+	return mapper_ret
 
 
 # TODO: implement
 def validate(self, storage_report, request):
-    #return 'size has to be within limits'
-    #return request
-    #return 'OK'
-
-    object_type = request['object_type']
-    mapper_id = request['mapper_id']
-
-    props = None
-    content_props = None
-
-    if object_type == 'bd' or object_type == 'bd_template':
-        path = request[PT_PATH]
-        bd_data = get_bd_data(self, storage_report, mapper_id, path)
-        props = bd_data['props']
-        if path != 'new_snapshot':
-            selected_content_id = request['content_id']
-            for c_data in bd_data['contents']:
-                if c_data['id'] == selected_content_id:
-                    content_props = c_data['props']
-    elif object_type == 'mapper':
-        props = get_mapper_data(self, storage_report, mapper_id)['props']
-    elif object_type == 'mapper_template':
-        mapper_type = request['mapper_type']
-        data = get_mapper_template_data(self, storage_report, mapper_type)
-        # find sources
-        sources_num = 0
-        for v in request.keys():
-            if v.find('source_bd_') == 0:
-                if request[v] == 'on':
-                    sources_num += 1
-        if sources_num < int(data['min_sources']) or sources_num > int(data['max_sources']):
-            return 'BAD: Invalid number of %s selected' % data['pretty_sources_name']
-        props = data['props']
-    elif object_type == 'add_sources':
-        data = get_mapper_data(self, storage_report, mapper_id)
-        # find sources
-        sources_num = 0
-        for v in request.keys():
-            if v.find('source_bd_') == 0:
-                if request[v] == 'on':
-                    sources_num += 1
-        if sources_num == 0 or sources_num > len(data['new_sources']):
-            return 'BAD: Invalid number of %s selected' % data['pretty_sources_name']
-
-    if props is not None:
-        res = check_props(self, props, request)
-        if res[0] is False:
-            return '%s %s' % (res[1], res[2])
-
-    if content_props is not None:
-        res = check_props(self, content_props, request)
-        if res[0] is False:
-            return '%s %s' % (res[1], res[2])
+	#return 'size has to be within limits'
+	#return request
+	#return 'OK'
+
+	object_type = request['object_type']
+	mapper_id = request['mapper_id']
+
+	props = None
+	content_props = None
+
+	if object_type == 'bd' or object_type == 'bd_template':
+		path = request[PT_PATH]
+		bd_data = get_bd_data(self, storage_report, mapper_id, path)
+		props = bd_data['props']
+		if path != 'new_snapshot':
+			selected_content_id = request['content_id']
+			for c_data in bd_data['contents']:
+				if c_data['id'] == selected_content_id:
+					content_props = c_data['props']
+	elif object_type == 'mapper':
+		props = get_mapper_data(self, storage_report, mapper_id)['props']
+	elif object_type == 'mapper_template':
+		mapper_type = request['mapper_type']
+		data = get_mapper_template_data(self, storage_report, mapper_type)
+		# find sources
+		sources_num = 0
+		for v in request.keys():
+			if v.find('source_bd_') == 0:
+				if request[v] == 'on':
+					sources_num += 1
+		if sources_num < int(data['min_sources']) or sources_num > int(data['max_sources']):
+			return 'BAD: Invalid number of %s selected' % data['pretty_sources_name']
+		props = data['props']
+	elif object_type == 'add_sources':
+		data = get_mapper_data(self, storage_report, mapper_id)
+		# find sources
+		sources_num = 0
+		for v in request.keys():
+			if v.find('source_bd_') == 0:
+				if request[v] == 'on':
+					sources_num += 1
+		if sources_num == 0 or sources_num > len(data['new_sources']):
+			return 'BAD: Invalid number of %s selected' % data['pretty_sources_name']
+
+	if props is not None:
+		res = check_props(self, props, request)
+		if res[0] is False:
+			return '%s %s' % (res[1], res[2])
+
+	if content_props is not None:
+		res = check_props(self, content_props, request)
+		if res[0] is False:
+			return '%s %s' % (res[1], res[2])
 
-    return 'OK'
+	return 'OK'
 
 def check_props(self, props, request):
-    valid = True
-    var_name = ''
-    msg = 'no message - BUG'
-
-    for prop_name in props:
-        if prop_name in request:
-            prop = props[prop_name]
-            req_value = request[prop_name]
-            if prop['type'] == 'int':
-                if prop['units'] != 'bytes':
-                    try:
-                        req_value = int(req_value)
-                    except:
-                        msg = '%s is missing an integer value' % prop['pretty_name']
-                        var_name = prop_name
-                        valid = False
-                        break
-                    min_val = int(prop['validation']['min'])
-                    max_val = int(prop['validation']['max'])
-                    step = int(prop['validation']['step'])
-                    r_val = (req_value / step) * step
-                    if r_val > max_val or r_val < min_val:
-                        msg = '%s has to be within range %d-%d %s' \
-                          % (prop['pretty_name'], min_val, max_val, prop['units'])
-                        var_name = prop_name
-                        valid = False
-                        break
-                else:
-                    try:
-                        req_value = float(req_value)
-                    except:
-                        msg = '%s is missing a float value' % prop['pretty_name']
-                        var_name = prop_name
-                        valid = False
-                        break
-                    dummy, units = bytes_to_value_prefunits(self, prop['value'])
-                    min_val  = float(convert_bytes(prop['validation']['min'], units))
-                    max_val  = float(convert_bytes(prop['validation']['max'], units))
-                    step = float(convert_bytes(prop['validation']['step'], units))
-                    if step < 0.000001:
-                        step = 0.000001
-                    r_val = (req_value / step) * step
-                    if r_val > max_val or r_val < min_val:
-                        msg = '%s has to be within range %d-%d %s' \
-                          % (prop['pretty_name'], min_val, max_val, units)
-                        var_name = prop_name
-                        valid = False
-                        break
-            elif prop['type'] == 'text':
-                if len(req_value) < int(prop['validation']['min_length']):
-                    msg = '%s has to have minimum length of %s' \
-                      % (prop['pretty_name'], prop['validation']['min_length'])
-                    var_name = prop_name
-                    valid = False
-                    break
-                elif len(req_value) > int(prop['validation']['max_length']):
-                    msg = '%s has to have maximum length of %s' \
-                      % (prop['pretty_name'], prop['validation']['max_length'])
-                    var_name = prop_name
-                    valid = False
-                    break
-                elif req_value in prop['validation']['reserved_words'].split(';') and req_value != '':
-                    msg = '%s contains reserved keyword. \nReserved keywords are %s' % (prop['pretty_name'], prop['validation']['reserved_words'].replace(';', ', '))
-                    var_name = prop_name
-                    valid = False
-                    break
-                # check illegal chars
-                for ch in prop['validation']['illegal_chars']:
-                    if ch in req_value and ch != '':
-                        msg = '%s contains illegal characters. \nIllegal characters are %s' % (prop['pretty_name'],  prop['validation']['illegal_chars'].replace(';', ', '))
-                        var_name = prop_name
-                        valid = False
-                        break
+	valid = True
+	var_name = ''
+	msg = 'no message - BUG'
+
+	for prop_name in props:
+		if prop_name in request:
+			prop = props[prop_name]
+			req_value = request[prop_name]
+			if prop['type'] == 'int':
+				if prop['units'] != 'bytes':
+					try:
+						req_value = int(req_value)
+					except:
+						msg = '%s is missing an integer value' % prop['pretty_name']
+						var_name = prop_name
+						valid = False
+						break
+					min_val = int(prop['validation']['min'])
+					max_val = int(prop['validation']['max'])
+					step = int(prop['validation']['step'])
+					r_val = (req_value / step) * step
+					if r_val > max_val or r_val < min_val:
+						msg = '%s has to be within range %d-%d %s' \
+								% (prop['pretty_name'], min_val, max_val, prop['units'])
+						var_name = prop_name
+						valid = False
+						break
+				else:
+					try:
+						req_value = float(req_value)
+					except:
+						msg = '%s is missing a float value' % prop['pretty_name']
+						var_name = prop_name
+						valid = False
+						break
+					dummy, units = bytes_to_value_prefunits(self, prop['value'])
+					min_val = float(convert_bytes(prop['validation']['min'], units))
+					max_val = float(convert_bytes(prop['validation']['max'], units))
+					step = float(convert_bytes(prop['validation']['step'], units))
+					if step < 0.000001:
+						step = 0.000001
+					r_val = (req_value / step) * step
+					if r_val > max_val or r_val < min_val:
+						msg = '%s has to be within range %d-%d %s' \
+								% (prop['pretty_name'], min_val, max_val, units)
+						var_name = prop_name
+						valid = False
+						break
+			elif prop['type'] == 'text':
+				if len(req_value) < int(prop['validation']['min_length']):
+					msg = '%s has to have minimum length of %s' \
+							% (prop['pretty_name'], prop['validation']['min_length'])
+					var_name = prop_name
+					valid = False
+					break
+				elif len(req_value) > int(prop['validation']['max_length']):
+					msg = '%s has to have maximum length of %s' \
+							% (prop['pretty_name'], prop['validation']['max_length'])
+					var_name = prop_name
+					valid = False
+					break
+				elif req_value in prop['validation']['reserved_words'].split(';') and req_value != '':
+					msg = '%s contains reserved keyword. \nReserved keywords are %s' % (prop['pretty_name'], prop['validation']['reserved_words'].replace(';', ', '))
+					var_name = prop_name
+					valid = False
+					break
+				# check illegal chars
+				for ch in prop['validation']['illegal_chars']:
+					if ch in req_value and ch != '':
+						msg = '%s contains illegal characters. \nIllegal characters are %s' \
+								% (prop['pretty_name'], prop['validation']['illegal_chars'].replace(';', ', '))
+						var_name = prop_name
+						valid = False
+						break
 
-    return [valid, var_name, msg]
+	return [valid, var_name, msg]
 
 
 
 def apply_storage_changes(self, ricci, storage_report, request):
-    if validate(self, storage_report, request) != 'OK':
-        raise Exception, 'Internal error: input not validated!!!'
-
-    session = request.SESSION
-
-    storagename = request['storagename']
-
-    object_type = request['object_type']
-    mapper_id = request[PT_MAPPER_ID]
-    mapper_type = request[PT_MAPPER_TYPE]
-    action_type = request['action_type']
-    path = ''
-    if request.has_key(PT_PATH):
-        path = request[PT_PATH]
-
-
-    batch_id = ''
-
-    if object_type == 'bd':
-        bd_data = get_bd_data(self, storage_report, mapper_id, path)
-        bd_xml = bd_data['xml']#.cloneNode(True)
-
-        if action_type == 'Remove':
-            doc = minidom.Document()
-            batch = doc.createElement("batch")
-            module = doc.createElement("module")
-            module.setAttribute("name", "storage")
-            req = doc.createElement("request")
-            req.setAttribute("API_version", "1.0")
-            req.setAttribute("sequence", "10")
-            f_call = doc.createElement("function_call")
-            f_call.setAttribute('name', 'remove_bd')
-            #f_call.appendChild(Variable('bd', bd_xml.cloneNode(True)).export_xml(doc))
-            f_call.appendChild(Variable('bd', bd_xml).export_xml(doc))
-
-            req.appendChild(f_call)
-            module.appendChild(req)
-            batch.appendChild(module)
-
-            res = ricci.process_batch(batch, True)
-            batch_id = res.getAttribute('batch_id')
-
-
-        elif action_type == 'Apply':
-            # BD props
-            props_xml = None
-            for node in bd_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == PROPS_TAG:
-                        props_xml = node
-            for node in props_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == VARIABLE_TAG:
-                        if node.getAttribute('mutable') == 'true':
-                            var_name = node.getAttribute('name')
-                            if var_name in request:
-                                if bd_data['props'][var_name]['type'] == 'int':
-                                    if bd_data['props'][var_name]['units'] != 'bytes':
-                                        val = int(request[var_name])
-                                        step = int(bd_data['props'][var_name]['validation']['step'])
-                                        val = (val / step) * step
-                                    else:
-                                        dummy, units = bytes_to_value_prefunits(self,
-                                                                                bd_data['props'][var_name]['value'])
-                                        min_val  = int(bd_data['props'][var_name]['validation']['min'])
-                                        max_val  = int(bd_data['props'][var_name]['validation']['max'])
-                                        step = int(bd_data['props'][var_name]['validation']['step'])
-                                        val_units = float(request[var_name])
-                                        val = int(val_units * get_units_multiplier(units))
-                                        val = (val / step) * step
-                                        if val < min_val:
-                                            val = min_val
-                                        if val > max_val:
-                                            val = max_val
-                                    node.setAttribute('value', str(val))
-                                else:
-                                    node.setAttribute('value', request[var_name])
-
-            # content
-            content_data_list = get_content_data_internal(session, bd_xml)
-            current_content_id = content_data_list[0]['id']
-            selected_content_id = request['content_id']
-            selected_content = None
-            selected_content_data = None
-            for c_data in content_data_list:
-                if c_data['id'] == selected_content_id:
-                    selected_content_data = c_data
-                    selected_content = c_data['xml']#.cloneNode(True)
-
-            # update selected_content props
-            props_xml = None
-            for node in selected_content.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == PROPS_TAG:
-                        props_xml = node
-            for node in props_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == VARIABLE_TAG:
-                        if node.getAttribute('mutable') == 'true':
-                            var_name = node.getAttribute('name')
-                            req_name = 'content_variable_%s_%s' % (selected_content_id, var_name)
-                            if req_name in request:
-                                if selected_content_data['props'][req_name]['type'] == 'int':
-                                    if selected_content_data['props'][req_name]['units'] != 'bytes':
-                                        val = int(request[req_name])
-                                        step = int(selected_content_data['props'][req_name]['validation']['step'])
-                                        val = (val / step) * step
-                                    else:
-                                        dummy, units = bytes_to_value_prefunits(self,
-                                                                                selected_content_data['props'][req_name]['value'])
-                                        min_val  = int(selected_content_data['props'][req_name]['validation']['min'])
-                                        max_val  = int(selected_content_data['props'][req_name]['validation']['max'])
-                                        step = int(selected_content_data['props'][req_name]['validation']['step'])
-                                        val_units = float(request[req_name])
-                                        val = int(val_units * get_units_multiplier(units))
-                                        val = (val / step) * step
-                                        if val < min_val:
-                                            val = min_val
-                                        if val > max_val:
-                                            val = max_val
-                                    node.setAttribute('value', str(val))
-                                else:
-                                    node.setAttribute('value', request[req_name])
-
-            if current_content_id == selected_content_id:
-                # no change of content
-                # replace content_xml
-                for node in bd_xml.childNodes:
-                    if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                        if node.nodeName == 'content':
-                            bd_xml.removeChild(node)
-                            bd_xml.appendChild(selected_content)
-                            break
-            else:
-                # content changed
-                # place it under <new_content>
-                for node in bd_xml.childNodes:
-                    if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                        if node.nodeName == 'content':
-                            for node2 in node.childNodes:
-                                if node2.nodeType == xml.dom.Node.ELEMENT_NODE:
-                                    if node2.nodeName == 'new_content':
-                                        node2.appendChild(selected_content)
-                                        break
-            #return bd_xml.toprettyxml()
-            doc = minidom.Document()
-            batch = doc.createElement("batch")
-            module = doc.createElement("module")
-            module.setAttribute("name", "storage")
-            req = doc.createElement("request")
-            req.setAttribute("API_version", "1.0")
-            req.setAttribute("sequence", "10")
-            f_call = doc.createElement("function_call")
-            f_call.setAttribute('name', 'modify_bd')
-            f_call.appendChild(Variable('bd', bd_xml).export_xml(doc))
-
-            req.appendChild(f_call)
-            module.appendChild(req)
-            batch.appendChild(module)
-
-            res = ricci.process_batch(batch, True)
-            batch_id = res.getAttribute('batch_id')
-
-
-    elif object_type == 'bd_template':
-        path = request[PT_PATH]
-        bd_data = get_bd_data(self, storage_report, mapper_id, path)
-        bd_xml = bd_data['xml']#.cloneNode(True)
-        #return bd_xml.toprettyxml()
-
-        if action_type == 'Apply': # Create
-            # BD props
-            props_xml = None
-            for node in bd_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == PROPS_TAG:
-                        props_xml = node
-            for node in props_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == VARIABLE_TAG:
-                        if node.getAttribute('mutable') == 'true':
-                            var_name = node.getAttribute('name')
-                            if var_name in request:
-                                if bd_data['props'][var_name]['type'] == 'int':
-                                    if bd_data['props'][var_name]['units'] != 'bytes':
-                                        val = int(request[var_name])
-                                        step = int(bd_data['props'][var_name]['validation']['step'])
-                                        val = (val / step) * step
-                                    else:
-                                        dummy, units = bytes_to_value_prefunits(self,
-                                                                                bd_data['props'][var_name]['value'])
-                                        min_val  = int(bd_data['props'][var_name]['validation']['min'])
-                                        max_val  = int(bd_data['props'][var_name]['validation']['max'])
-                                        step = int(bd_data['props'][var_name]['validation']['step'])
-                                        val_units = float(request[var_name])
-                                        val = int(val_units * get_units_multiplier(units))
-                                        val = (val / step) * step
-                                        if val < min_val:
-                                            val = min_val
-                                        if val > max_val:
-                                            val = max_val
-                                    node.setAttribute('value', str(val))
-                                else:
-                                    node.setAttribute('value', request[var_name])
-
-            if path != 'new_snapshot':
-                # content
-                content_data_list = get_content_data_internal(session, bd_xml)
-                current_content_id = content_data_list[0]['id']
-                selected_content_id = request['content_id']
-                selected_content = None
-                selected_content_data = None
-                for c_data in content_data_list:
-                    if c_data['id'] == selected_content_id:
-                        selected_content_data = c_data
-                        selected_content = c_data['xml']#.cloneNode(True)
-
-                # update selected_content props
-                props_xml = None
-                for node in selected_content.childNodes:
-                    if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                        if node.nodeName == PROPS_TAG:
-                            props_xml = node
-                for node in props_xml.childNodes:
-                    if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                        if node.nodeName == VARIABLE_TAG:
-                            if node.getAttribute('mutable') == 'true':
-                                var_name = node.getAttribute('name')
-                                req_name = 'content_variable_%s_%s' % (selected_content_id, var_name)
-                                if req_name in request:
-                                    if selected_content_data['props'][req_name]['type'] == 'int':
-                                        if selected_content_data['props'][req_name]['units'] != 'bytes':
-                                            val = int(request[req_name])
-                                            step = int(selected_content_data['props'][req_name]['validation']['step'])
-                                            val = (val / step) * step
-                                        else:
-                                            dummy, units = bytes_to_value_prefunits(self,
-                                                                                    selected_content_data['props'][req_name]['value'])
-                                            min_val  = int(selected_content_data['props'][req_name]['validation']['min'])
-                                            max_val  = int(selected_content_data['props'][req_name]['validation']['max'])
-                                            step = int(selected_content_data['props'][req_name]['validation']['step'])
-                                            val_units = float(request[req_name])
-                                            val = int(val_units * get_units_multiplier(units))
-                                            val = (val / step) * step
-                                            if val < min_val:
-                                                val = min_val
-                                            if val > max_val:
-                                                val = max_val
-                                        node.setAttribute('value', str(val))
-                                    else:
-                                        node.setAttribute('value', request[req_name])
-
-                if current_content_id == selected_content_id:
-                    # no change of content
-                    # replace content_xml
-                    for node in bd_xml.childNodes:
-                        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                            if node.nodeName == 'content':
-                                bd_xml.removeChild(node)
-                                bd_xml.appendChild(selected_content)
-                                break
-                else:
-                    # content changed
-                    # place it under <new_content>
-                    for node in bd_xml.childNodes:
-                        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                            if node.nodeName == 'content':
-                                for node2 in node.childNodes:
-                                    if node2.nodeType == xml.dom.Node.ELEMENT_NODE:
-                                        if node2.nodeName == 'new_content':
-                                            node2.appendChild(selected_content)
-                                            break
-            #return bd_xml.toprettyxml()
-            doc = minidom.Document()
-            batch = doc.createElement("batch")
-            module = doc.createElement("module")
-            module.setAttribute("name", "storage")
-            req = doc.createElement("request")
-            req.setAttribute("API_version", "1.0")
-            req.setAttribute("sequence", "10")
-            f_call = doc.createElement("function_call")
-            f_call.setAttribute('name', 'create_bd')
-            f_call.appendChild(Variable('bd', bd_xml).export_xml(doc))
-
-            req.appendChild(f_call)
-            module.appendChild(req)
-            batch.appendChild(module)
-
-            res = ricci.process_batch(batch, True)
-            batch_id = res.getAttribute('batch_id')
-
-
-
-    elif object_type == 'mapper':
-        mapper_data = get_mapper_data(self, storage_report, mapper_id)
-        mapper_xml = mapper_data['xml']#.cloneNode(True)
-        #return mapper_xml.toprettyxml()
-
-        if action_type == 'Remove':
-            doc = minidom.Document()
-            batch = doc.createElement("batch")
-            module = doc.createElement("module")
-            module.setAttribute("name", "storage")
-            req = doc.createElement("request")
-            req.setAttribute("API_version", "1.0")
-            req.setAttribute("sequence", "10")
-            f_call = doc.createElement("function_call")
-            f_call.setAttribute('name', 'remove_mapper')
-            f_call.appendChild(Variable('mapper', mapper_xml).export_xml(doc))
-
-            req.appendChild(f_call)
-            module.appendChild(req)
-            batch.appendChild(module)
-
-            res = ricci.process_batch(batch, True)
-            batch_id = res.getAttribute('batch_id')
-
-
-        elif action_type == 'Apply':
-            # props
-            props_xml = None
-            for node in mapper_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == PROPS_TAG:
-                        props_xml = node
-            for node in props_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == VARIABLE_TAG:
-                        if node.getAttribute('mutable') == 'true':
-                            var_name = node.getAttribute('name')
-                            if var_name in request:
-                                if mapper_data['props'][var_name]['type'] == 'int':
-                                    if mapper_data['props'][var_name]['units'] != 'bytes':
-                                        val = int(request[var_name])
-                                        step = int(mapper_data['props'][var_name]['validation']['step'])
-                                        val = (val / step) * step
-                                    else:
-                                        dummy, units = bytes_to_value_prefunits(self,
-                                                                                mapper_data['props'][var_name]['value'])
-                                        min_val  = int(mapper_data['props'][var_name]['validation']['min'])
-                                        max_val  = int(mapper_data['props'][var_name]['validation']['max'])
-                                        step = int(mapper_data['props'][var_name]['validation']['step'])
-                                        val_units = float(request[var_name])
-                                        val = int(val_units * get_units_multiplier(units))
-                                        val = (val / step) * step
-                                        if val < min_val:
-                                            val = min_val
-                                        if val > max_val:
-                                            val = max_val
-                                    node.setAttribute('value', str(val))
-                                else:
-                                    node.setAttribute('value', request[var_name])
-            #return mapper_xml.toprettyxml()
-            doc = minidom.Document()
-            batch = doc.createElement("batch")
-            module = doc.createElement("module")
-            module.setAttribute("name", "storage")
-            req = doc.createElement("request")
-            req.setAttribute("API_version", "1.0")
-            req.setAttribute("sequence", "10")
-            f_call = doc.createElement("function_call")
-            f_call.setAttribute('name', 'modify_mapper')
-            f_call.appendChild(Variable('mapper', mapper_xml).export_xml(doc))
-
-            req.appendChild(f_call)
-            module.appendChild(req)
-            batch.appendChild(module)
-
-            res = ricci.process_batch(batch, True)
-            batch_id = res.getAttribute('batch_id')
-
-
-
-    elif object_type == 'mapper_template':
-        mapper_data = get_mapper_template_data(self, storage_report, mapper_type)
-        mapper_xml = mapper_data['xml']#.cloneNode(True)
-        #return mapper_xml.toprettyxml()
-
-        if action_type == 'Apply':
-            # props
-            props_xml = None
-            for node in mapper_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == PROPS_TAG:
-                        props_xml = node
-            for node in props_xml.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == VARIABLE_TAG:
-                        if node.getAttribute('mutable') == 'true':
-                            var_name = node.getAttribute('name')
-                            if request.has_key(var_name):
-                                if mapper_data['props'][var_name]['type'] == 'int':
-                                    if mapper_data['props'][var_name]['units'] != 'bytes':
-                                        val = int(request[var_name])
-                                        step = int(mapper_data['props'][var_name]['validation']['step'])
-                                        val = (val / step) * step
-                                    else:
-                                        dummy, units = bytes_to_value_prefunits(self,
-                                                                                mapper_data['props'][var_name]['value'])
-                                        min_val  = int(mapper_data['props'][var_name]['validation']['min'])
-                                        max_val  = int(mapper_data['props'][var_name]['validation']['max'])
-                                        step = int(mapper_data['props'][var_name]['validation']['step'])
-                                        val_units = float(request[var_name])
-                                        val = int(val_units * get_units_multiplier(units))
-                                        val = (val / step) * step
-                                        if val < min_val:
-                                            val = min_val
-                                        if val > max_val:
-                                            val = max_val
-                                    node.setAttribute('value', str(val))
-                                else:
-                                    node.setAttribute('value', request[var_name])
-
-            # find sources
-            for v in request.keys():
-                if v.find('source_bd_') == 0:
-                    if request[v] == 'on':
-                        path = v[len('source_bd_'):]
-                        for s_xml in storage_report.get_new_sources(mapper_xml):
-                            if s_xml.getAttribute('path') == path:
-                                for node in mapper_xml.childNodes:
-                                    if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                                        if node.nodeName == MAPPER_SOURCES_TAG:
-                                            node.appendChild(s_xml)#.cloneNode(True))
-            #return mapper_xml.toprettyxml()
-            doc = minidom.Document()
-            batch = doc.createElement("batch")
-            module = doc.createElement("module")
-            module.setAttribute("name", "storage")
-            req = doc.createElement("request")
-            req.setAttribute("API_version", "1.0")
-            req.setAttribute("sequence", "10")
-            f_call = doc.createElement("function_call")
-            f_call.setAttribute('name', 'create_mapper')
-#            f_call.appendChild(Variable('mapper', mapper_xml.cloneNode(True)).export_xml(doc))
-            f_call.appendChild(Variable('mapper', mapper_xml).export_xml(doc))
-
-            req.appendChild(f_call)
-            module.appendChild(req)
-            batch.appendChild(module)
-
-            res = ricci.process_batch(batch, True)
-            batch_id = res.getAttribute('batch_id')
-
-
-
-
-    elif object_type == 'add_sources':
-        mapper_data = get_mapper_data(self, storage_report, mapper_id)
-        mapper_xml = mapper_data['xml']#.cloneNode(True)
-        new_sources = []
-        #return mapper_xml.toprettyxml()
-
-        if action_type == 'Apply':
-            # find sources
-            for v in request.keys():
-                if v.find('source_bd_') == 0:
-                    if request[v] == 'on':
-                        path = v[len('source_bd_'):]
-                        for ns in mapper_data['new_sources']:
-                            if ns['path'] == path:
-                                new_sources.append(ns['xml'])#.cloneNode(True))
-            #return mapper_xml.toprettyxml()
-            doc = minidom.Document()
-            batch = doc.createElement("batch")
-            module = doc.createElement("module")
-            module.setAttribute("name", "storage")
-            req = doc.createElement("request")
-            req.setAttribute("API_version", "1.0")
-            req.setAttribute("sequence", "11")
-            f_call = doc.createElement("function_call")
-            f_call.setAttribute('name', 'add_mapper_sources')
-            f_call.appendChild(Variable('mapper_type', mapper_type).export_xml(doc))
-            f_call.appendChild(Variable('mapper_id', mapper_id).export_xml(doc))
-            f_call.appendChild(Variable('mapper_state_ind', mapper_xml.getAttribute('state_ind')).export_xml(doc))
-            f_call.appendChild(VariableList('bds', new_sources, [], VARIABLE_TYPE_LIST_XML).export_xml(doc))
-
-            req.appendChild(f_call)
-            module.appendChild(req)
-            batch.appendChild(module)
-
-            res = ricci.process_batch(batch, True)
-            batch_id = res.getAttribute('batch_id')
-
-
-    if batch_id == '':
-        raise Exception, 'unsupported function'
-    else:
-        invalidate_storage_report(request.SESSION, storagename)
-        return batch_id
-
-
-def get_storage_batch_result(self,
-                             storagename,
-                             ricci,
-                             index_html_URL,
-                             batch_id):
-    error     = True               # ricci reported failure or no ricci
-    completed = False              # no batch, or batch done (defined if no error)
-    url       = index_html_URL     # redirect URL
-    msg       = 'Unknown error occured'
-
-    if ricci is None:
-        # ricci down
-        error   = True
-        url     = url
-        msg     = 'Unable to contact %s' % storagename
-    else:
-        batch = 'no batch'
-        try:
-            batch = ricci.batch_report(batch_id)
-        except:
-            pass
-        if batch == 'no batch':
-            error = True
-            url   = url
-            msg   = 'Ricci on %s responded with error. No detailed info available.' % storagename
-        elif batch is None:
-            # no such batch
-            error     = False
-            completed = True
-            url       = '%s?%s=%s&%s=%s' \
-                % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-            msg       = 'No such batch'
-        else:
-            DEFAULT_ERROR = 'extract_module_status() failed'
-            code, err_msg = DEFAULT_ERROR, ''
-            try:
-                code, err_msg = extract_module_status(batch, 1)
-            except:
-                pass
-            if code == DEFAULT_ERROR:
-                error = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg   = 'Ricci on %s sent a malformed response' % storagename
-            elif code == -101 or code == -102:
-                # in progress
-                error     = False
-                completed = False
-                msg   = 'Task still in progress'
-            elif code == -103:
-                # module removed from scheduler
-                error = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg   = 'Ricci on %s removed request from scheduler. File bug report against ricci.' % storagename
-            elif code == -104:
-                # module failure
-                error = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg   = 'Ricci on %s failed to execute storage module; reinstall it.' % storagename
-            elif code == -2:
-                # API error
-                error = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg   = 'Luci server used invalid API to communicate with %s. File a bug report against luci.' % storagename
-            elif code == -1:
-                # undefined error
-                error = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg   = 'Reason for failure (as reported by %s): %s' % (storagename, err_msg)
-            elif code == 0:
-                # no error
-                error     = False
-                completed = True
-                # TODO: implement proper redirect
-                url       = get_commit_redirect(url,
-                                                storagename,
-                                                batch)
-                msg       = 'Done successfully'
-            elif code == 1:
-                # mid-air
-                error  = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg    = 'Mid-Air collision (storage on %s has changed since last probe).' % storagename
-            elif code == 2:
-                # validation error
-                error  = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg    = 'Validation error. File bug report against Luci.'
-            elif code == 3:
-                # unmount error
-                error  = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg    = 'Unmount failure: %s' % err_msg
-            elif code == 4:
-                # clvmd error
-                error  = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg    = 'clvmd (clustered LVM daemon) is not running on %s' % storagename
-            elif code == 5:
-                # not quorate
-                error  = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg    = 'Cluster quorum is required, and yet cluster is not quorate. Start cluster, and try again.'
-            elif code == 6:
-                # LVM cluster locking not enabled
-                error  = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg    = 'LVM cluster locking is not enabled on %s' % storagename
-            elif code == 7:
-                # cluster not running
-                error  = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg    = 'Cluster infrastructure is not running on %s' % storagename
-            elif code > 8:
-                error  = True
-                url   = '%s?%s=%s&%s=%s' \
-                    % (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
-                msg    = err_msg
-
-    return {'error'        : error,
-            'completed'    : completed,
-            'redirect_url' : url,
-            'msg'          : msg}
+	if validate(self, storage_report, request) != 'OK':
+		raise Exception, 'Internal error: input not validated!!!'
 
+	session = request.SESSION
 
+	storagename = request['storagename']
 
+	object_type = request['object_type']
+	mapper_id = request[PT_MAPPER_ID]
+	mapper_type = request[PT_MAPPER_TYPE]
+	action_type = request['action_type']
+	path = ''
+	if request.has_key(PT_PATH):
+		path = request[PT_PATH]
+
+
+	batch_id = ''
+
+	if object_type == 'bd':
+		bd_data = get_bd_data(self, storage_report, mapper_id, path)
+		bd_xml = bd_data['xml']#.cloneNode(True)
+
+		if action_type == 'Remove':
+			doc = minidom.Document()
+			batch = doc.createElement("batch")
+			module = doc.createElement("module")
+			module.setAttribute("name", "storage")
+			req = doc.createElement("request")
+			req.setAttribute("API_version", "1.0")
+			req.setAttribute("sequence", "10")
+			f_call = doc.createElement("function_call")
+			f_call.setAttribute('name', 'remove_bd')
+			#f_call.appendChild(Variable('bd', bd_xml.cloneNode(True)).export_xml(doc))
+			f_call.appendChild(Variable('bd', bd_xml).export_xml(doc))
+
+			req.appendChild(f_call)
+			module.appendChild(req)
+			batch.appendChild(module)
+
+			res = ricci.process_batch(batch, True)
+			batch_id = res.getAttribute('batch_id')
+
+
+		elif action_type == 'Apply':
+			# BD props
+			props_xml = None
+			for node in bd_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == PROPS_TAG:
+						props_xml = node
+			for node in props_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == VARIABLE_TAG:
+						if node.getAttribute('mutable') == 'true':
+							var_name = node.getAttribute('name')
+							if var_name in request:
+								if bd_data['props'][var_name]['type'] == 'int':
+									if bd_data['props'][var_name]['units'] != 'bytes':
+										val = int(request[var_name])
+										step = int(bd_data['props'][var_name]['validation']['step'])
+										val = (val / step) * step
+									else:
+										dummy, units = bytes_to_value_prefunits(self,
+															bd_data['props'][var_name]['value'])
+										min_val = int(bd_data['props'][var_name]['validation']['min'])
+										max_val = int(bd_data['props'][var_name]['validation']['max'])
+										step = int(bd_data['props'][var_name]['validation']['step'])
+										val_units = float(request[var_name])
+										val = int(val_units * get_units_multiplier(units))
+										val = (val / step) * step
+										if val < min_val:
+											val = min_val
+										if val > max_val:
+											val = max_val
+									node.setAttribute('value', str(val))
+								else:
+									node.setAttribute('value', request[var_name])
+
+			# content
+			content_data_list = get_content_data_internal(session, bd_xml)
+			current_content_id = content_data_list[0]['id']
+			selected_content_id = request['content_id']
+			selected_content = None
+			selected_content_data = None
+			for c_data in content_data_list:
+				if c_data['id'] == selected_content_id:
+					selected_content_data = c_data
+					selected_content = c_data['xml']#.cloneNode(True)
+
+			# update selected_content props
+			props_xml = None
+			for node in selected_content.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == PROPS_TAG:
+						props_xml = node
+			for node in props_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == VARIABLE_TAG:
+						if node.getAttribute('mutable') == 'true':
+							var_name = node.getAttribute('name')
+							req_name = 'content_variable_%s_%s' % (selected_content_id, var_name)
+							if req_name in request:
+								if selected_content_data['props'][req_name]['type'] == 'int':
+									if selected_content_data['props'][req_name]['units'] != 'bytes':
+										val = int(request[req_name])
+										step = int(selected_content_data['props'][req_name]['validation']['step'])
+										val = (val / step) * step
+									else:
+										dummy, units = bytes_to_value_prefunits(self,
+															selected_content_data['props'][req_name]['value'])
+										min_val = int(selected_content_data['props'][req_name]['validation']['min'])
+										max_val = int(selected_content_data['props'][req_name]['validation']['max'])
+										step = int(selected_content_data['props'][req_name]['validation']['step'])
+										val_units = float(request[req_name])
+										val = int(val_units * get_units_multiplier(units))
+										val = (val / step) * step
+										if val < min_val:
+											val = min_val
+										if val > max_val:
+											val = max_val
+									node.setAttribute('value', str(val))
+								else:
+									node.setAttribute('value', request[req_name])
+
+			if current_content_id == selected_content_id:
+				# no change of content
+				# replace content_xml
+				for node in bd_xml.childNodes:
+					if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+						if node.nodeName == 'content':
+							bd_xml.removeChild(node)
+							bd_xml.appendChild(selected_content)
+							break
+			else:
+				# content changed
+				# place it under <new_content>
+				for node in bd_xml.childNodes:
+					if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+						if node.nodeName == 'content':
+							for node2 in node.childNodes:
+								if node2.nodeType == xml.dom.Node.ELEMENT_NODE:
+									if node2.nodeName == 'new_content':
+										node2.appendChild(selected_content)
+										break
+			#return bd_xml.toprettyxml()
+			doc = minidom.Document()
+			batch = doc.createElement("batch")
+			module = doc.createElement("module")
+			module.setAttribute("name", "storage")
+			req = doc.createElement("request")
+			req.setAttribute("API_version", "1.0")
+			req.setAttribute("sequence", "10")
+			f_call = doc.createElement("function_call")
+			f_call.setAttribute('name', 'modify_bd')
+			f_call.appendChild(Variable('bd', bd_xml).export_xml(doc))
+
+			req.appendChild(f_call)
+			module.appendChild(req)
+			batch.appendChild(module)
+
+			res = ricci.process_batch(batch, True)
+			batch_id = res.getAttribute('batch_id')
+
+
+	elif object_type == 'bd_template':
+		path = request[PT_PATH]
+		bd_data = get_bd_data(self, storage_report, mapper_id, path)
+		bd_xml = bd_data['xml']#.cloneNode(True)
+		#return bd_xml.toprettyxml()
+
+		if action_type == 'Apply': # Create
+			# BD props
+			props_xml = None
+			for node in bd_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == PROPS_TAG:
+						props_xml = node
+			for node in props_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == VARIABLE_TAG:
+						if node.getAttribute('mutable') == 'true':
+							var_name = node.getAttribute('name')
+							if var_name in request:
+								if bd_data['props'][var_name]['type'] == 'int':
+									if bd_data['props'][var_name]['units'] != 'bytes':
+										val = int(request[var_name])
+										step = int(bd_data['props'][var_name]['validation']['step'])
+										val = (val / step) * step
+									else:
+										dummy, units = bytes_to_value_prefunits(self,
+																				bd_data['props'][var_name]['value'])
+										min_val = int(bd_data['props'][var_name]['validation']['min'])
+										max_val = int(bd_data['props'][var_name]['validation']['max'])
+										step = int(bd_data['props'][var_name]['validation']['step'])
+										val_units = float(request[var_name])
+										val = int(val_units * get_units_multiplier(units))
+										val = (val / step) * step
+										if val < min_val:
+											val = min_val
+										if val > max_val:
+											val = max_val
+									node.setAttribute('value', str(val))
+								else:
+									node.setAttribute('value', request[var_name])
+
+			if path != 'new_snapshot':
+				# content
+				content_data_list = get_content_data_internal(session, bd_xml)
+				current_content_id = content_data_list[0]['id']
+				selected_content_id = request['content_id']
+				selected_content = None
+				selected_content_data = None
+				for c_data in content_data_list:
+					if c_data['id'] == selected_content_id:
+						selected_content_data = c_data
+						selected_content = c_data['xml']#.cloneNode(True)
+
+				# update selected_content props
+				props_xml = None
+				for node in selected_content.childNodes:
+					if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+						if node.nodeName == PROPS_TAG:
+							props_xml = node
+				for node in props_xml.childNodes:
+					if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+						if node.nodeName == VARIABLE_TAG:
+							if node.getAttribute('mutable') == 'true':
+								var_name = node.getAttribute('name')
+								req_name = 'content_variable_%s_%s' % (selected_content_id, var_name)
+								if req_name in request:
+									if selected_content_data['props'][req_name]['type'] == 'int':
+										if selected_content_data['props'][req_name]['units'] != 'bytes':
+											val = int(request[req_name])
+											step = int(selected_content_data['props'][req_name]['validation']['step'])
+											val = (val / step) * step
+										else:
+											dummy, units = bytes_to_value_prefunits(self,
+																					selected_content_data['props'][req_name]['value'])
+											min_val = int(selected_content_data['props'][req_name]['validation']['min'])
+											max_val = int(selected_content_data['props'][req_name]['validation']['max'])
+											step = int(selected_content_data['props'][req_name]['validation']['step'])
+											val_units = float(request[req_name])
+											val = int(val_units * get_units_multiplier(units))
+											val = (val / step) * step
+											if val < min_val:
+												val = min_val
+											if val > max_val:
+												val = max_val
+										node.setAttribute('value', str(val))
+									else:
+										node.setAttribute('value', request[req_name])
+
+				if current_content_id == selected_content_id:
+					# no change of content
+					# replace content_xml
+					for node in bd_xml.childNodes:
+						if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+							if node.nodeName == 'content':
+								bd_xml.removeChild(node)
+								bd_xml.appendChild(selected_content)
+								break
+				else:
+					# content changed
+					# place it under <new_content>
+					for node in bd_xml.childNodes:
+						if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+							if node.nodeName == 'content':
+								for node2 in node.childNodes:
+									if node2.nodeType == xml.dom.Node.ELEMENT_NODE:
+										if node2.nodeName == 'new_content':
+											node2.appendChild(selected_content)
+											break
+			#return bd_xml.toprettyxml()
+			doc = minidom.Document()
+			batch = doc.createElement("batch")
+			module = doc.createElement("module")
+			module.setAttribute("name", "storage")
+			req = doc.createElement("request")
+			req.setAttribute("API_version", "1.0")
+			req.setAttribute("sequence", "10")
+			f_call = doc.createElement("function_call")
+			f_call.setAttribute('name', 'create_bd')
+			f_call.appendChild(Variable('bd', bd_xml).export_xml(doc))
+
+			req.appendChild(f_call)
+			module.appendChild(req)
+			batch.appendChild(module)
+
+			res = ricci.process_batch(batch, True)
+			batch_id = res.getAttribute('batch_id')
+
+	elif object_type == 'mapper':
+		mapper_data = get_mapper_data(self, storage_report, mapper_id)
+		mapper_xml = mapper_data['xml']#.cloneNode(True)
+		#return mapper_xml.toprettyxml()
+
+		if action_type == 'Remove':
+			doc = minidom.Document()
+			batch = doc.createElement("batch")
+			module = doc.createElement("module")
+			module.setAttribute("name", "storage")
+			req = doc.createElement("request")
+			req.setAttribute("API_version", "1.0")
+			req.setAttribute("sequence", "10")
+			f_call = doc.createElement("function_call")
+			f_call.setAttribute('name', 'remove_mapper')
+			f_call.appendChild(Variable('mapper', mapper_xml).export_xml(doc))
+
+			req.appendChild(f_call)
+			module.appendChild(req)
+			batch.appendChild(module)
+
+			res = ricci.process_batch(batch, True)
+			batch_id = res.getAttribute('batch_id')
+
+
+		elif action_type == 'Apply':
+			# props
+			props_xml = None
+			for node in mapper_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == PROPS_TAG:
+						props_xml = node
+			for node in props_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == VARIABLE_TAG:
+						if node.getAttribute('mutable') == 'true':
+							var_name = node.getAttribute('name')
+							if var_name in request:
+								if mapper_data['props'][var_name]['type'] == 'int':
+									if mapper_data['props'][var_name]['units'] != 'bytes':
+										val = int(request[var_name])
+										step = int(mapper_data['props'][var_name]['validation']['step'])
+										val = (val / step) * step
+									else:
+										dummy, units = bytes_to_value_prefunits(self,
+																				mapper_data['props'][var_name]['value'])
+										min_val = int(mapper_data['props'][var_name]['validation']['min'])
+										max_val = int(mapper_data['props'][var_name]['validation']['max'])
+										step = int(mapper_data['props'][var_name]['validation']['step'])
+										val_units = float(request[var_name])
+										val = int(val_units * get_units_multiplier(units))
+										val = (val / step) * step
+										if val < min_val:
+											val = min_val
+										if val > max_val:
+											val = max_val
+									node.setAttribute('value', str(val))
+								else:
+									node.setAttribute('value', request[var_name])
+			#return mapper_xml.toprettyxml()
+			doc = minidom.Document()
+			batch = doc.createElement("batch")
+			module = doc.createElement("module")
+			module.setAttribute("name", "storage")
+			req = doc.createElement("request")
+			req.setAttribute("API_version", "1.0")
+			req.setAttribute("sequence", "10")
+			f_call = doc.createElement("function_call")
+			f_call.setAttribute('name', 'modify_mapper')
+			f_call.appendChild(Variable('mapper', mapper_xml).export_xml(doc))
+
+			req.appendChild(f_call)
+			module.appendChild(req)
+			batch.appendChild(module)
+
+			res = ricci.process_batch(batch, True)
+			batch_id = res.getAttribute('batch_id')
+
+
+
+	elif object_type == 'mapper_template':
+		mapper_data = get_mapper_template_data(self, storage_report, mapper_type)
+		mapper_xml = mapper_data['xml']#.cloneNode(True)
+		#return mapper_xml.toprettyxml()
+
+		if action_type == 'Apply':
+			# props
+			props_xml = None
+			for node in mapper_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == PROPS_TAG:
+						props_xml = node
+			for node in props_xml.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == VARIABLE_TAG:
+						if node.getAttribute('mutable') == 'true':
+							var_name = node.getAttribute('name')
+							if request.has_key(var_name):
+								if mapper_data['props'][var_name]['type'] == 'int':
+									if mapper_data['props'][var_name]['units'] != 'bytes':
+										val = int(request[var_name])
+										step = int(mapper_data['props'][var_name]['validation']['step'])
+										val = (val / step) * step
+									else:
+										dummy, units = bytes_to_value_prefunits(self,
+																				mapper_data['props'][var_name]['value'])
+										min_val = int(mapper_data['props'][var_name]['validation']['min'])
+										max_val = int(mapper_data['props'][var_name]['validation']['max'])
+										step = int(mapper_data['props'][var_name]['validation']['step'])
+										val_units = float(request[var_name])
+										val = int(val_units * get_units_multiplier(units))
+										val = (val / step) * step
+										if val < min_val:
+											val = min_val
+										if val > max_val:
+											val = max_val
+									node.setAttribute('value', str(val))
+								else:
+									node.setAttribute('value', request[var_name])
+
+			# find sources
+			for v in request.keys():
+				if v.find('source_bd_') == 0:
+					if request[v] == 'on':
+						path = v[len('source_bd_'):]
+						for s_xml in storage_report.get_new_sources(mapper_xml):
+							if s_xml.getAttribute('path') == path:
+								for node in mapper_xml.childNodes:
+									if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+										if node.nodeName == MAPPER_SOURCES_TAG:
+											node.appendChild(s_xml)#.cloneNode(True))
+			#return mapper_xml.toprettyxml()
+			doc = minidom.Document()
+			batch = doc.createElement("batch")
+			module = doc.createElement("module")
+			module.setAttribute("name", "storage")
+			req = doc.createElement("request")
+			req.setAttribute("API_version", "1.0")
+			req.setAttribute("sequence", "10")
+			f_call = doc.createElement("function_call")
+			f_call.setAttribute('name', 'create_mapper')
+#			f_call.appendChild(Variable('mapper', mapper_xml.cloneNode(True)).export_xml(doc))
+			f_call.appendChild(Variable('mapper', mapper_xml).export_xml(doc))
+
+			req.appendChild(f_call)
+			module.appendChild(req)
+			batch.appendChild(module)
+
+			res = ricci.process_batch(batch, True)
+			batch_id = res.getAttribute('batch_id')
+
+
+
+
+	elif object_type == 'add_sources':
+		mapper_data = get_mapper_data(self, storage_report, mapper_id)
+		mapper_xml = mapper_data['xml']#.cloneNode(True)
+		new_sources = []
+		#return mapper_xml.toprettyxml()
+
+		if action_type == 'Apply':
+			# find sources
+			for v in request.keys():
+				if v.find('source_bd_') == 0:
+					if request[v] == 'on':
+						path = v[len('source_bd_'):]
+						for ns in mapper_data['new_sources']:
+							if ns['path'] == path:
+								new_sources.append(ns['xml'])#.cloneNode(True))
+			#return mapper_xml.toprettyxml()
+			doc = minidom.Document()
+			batch = doc.createElement("batch")
+			module = doc.createElement("module")
+			module.setAttribute("name", "storage")
+			req = doc.createElement("request")
+			req.setAttribute("API_version", "1.0")
+			req.setAttribute("sequence", "11")
+			f_call = doc.createElement("function_call")
+			f_call.setAttribute('name', 'add_mapper_sources')
+			f_call.appendChild(Variable('mapper_type', mapper_type).export_xml(doc))
+			f_call.appendChild(Variable('mapper_id', mapper_id).export_xml(doc))
+			f_call.appendChild(Variable('mapper_state_ind', mapper_xml.getAttribute('state_ind')).export_xml(doc))
+			f_call.appendChild(VariableList('bds', new_sources, [], VARIABLE_TYPE_LIST_XML).export_xml(doc))
+
+			req.appendChild(f_call)
+			module.appendChild(req)
+			batch.appendChild(module)
+
+			res = ricci.process_batch(batch, True)
+			batch_id = res.getAttribute('batch_id')
+
+
+	if batch_id == '':
+		raise Exception, 'unsupported function'
+	else:
+		invalidate_storage_report(request.SESSION, storagename)
+		return batch_id
+
+
+def get_storage_batch_result(self, storagename, ricci, index_html_URL, batch_id):
+	error = True			# ricci reported failure or no ricci
+	completed = False		# no batch, or batch done (defined if no error)
+	url = index_html_URL	# redirect URL
+	msg = 'Unknown error occured'
+
+	if ricci is None:
+		# ricci down
+		error = True
+		url = url
+		msg = 'Unable to contact %s' % storagename
+	else:
+		batch = 'no batch'
+		try:
+			batch = ricci.batch_report(batch_id)
+		except:
+			pass
+		if batch == 'no batch':
+			error = True
+			url = url
+			msg = 'Ricci on %s responded with error. No detailed info available.' % storagename
+		elif batch is None:
+			# no such batch
+			error = False
+			completed = True
+			url = '%s?%s=%s&%s=%s' \
+					% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+			msg = 'No such batch'
+		else:
+			DEFAULT_ERROR = 'extract_module_status() failed'
+			code, err_msg = DEFAULT_ERROR, ''
+			try:
+				code, err_msg = extract_module_status(batch, 1)
+			except:
+				pass
+			if code == DEFAULT_ERROR:
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+					% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Ricci on %s sent a malformed response' % storagename
+			elif code == -101 or code == -102:
+				# in progress
+				error = False
+				completed = False
+				msg = 'Task still in progress'
+			elif code == -103:
+				# module removed from scheduler
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+					% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Ricci on %s removed request from scheduler. File bug report against ricci.' % storagename
+			elif code == -104:
+				# module failure
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Ricci on %s failed to execute storage module; reinstall it.' % storagename
+			elif code == -2:
+				# API error
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Luci server used invalid API to communicate with %s. File a bug report against luci.' % storagename
+			elif code == -1:
+				# undefined error
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Reason for failure (as reported by %s): %s' % (storagename, err_msg)
+			elif code == 0:
+				# no error
+				error = False
+				completed = True
+				# TODO: implement proper redirect
+				url = get_commit_redirect(url, storagename, batch)
+				msg = 'Done successfully'
+			elif code == 1:
+				# mid-air
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Mid-Air collision (storage on %s has changed since last probe).' % storagename
+			elif code == 2:
+				# validation error
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Validation error. File bug report against Luci.'
+			elif code == 3:
+				# unmount error
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Unmount failure: %s' % err_msg
+			elif code == 4:
+				# clvmd error
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'clvmd (clustered LVM daemon) is not running on %s' % storagename
+			elif code == 5:
+				# not quorate
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Cluster quorum is required, but cluster is not quorate. Start cluster, and try again.'
+			elif code == 6:
+				# LVM cluster locking not enabled
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'LVM cluster locking is not enabled on %s' % storagename
+			elif code == 7:
+				# cluster not running
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = 'Cluster infrastructure is not running on %s' % storagename
+			elif code > 8:
+				error = True
+				url = '%s?%s=%s&%s=%s' \
+						% (index_html_URL, STONAME, storagename, PAGETYPE, STORAGE)
+				msg = err_msg
+
+	return {
+		'error': error,
+		'completed': completed,
+		'redirect_url': url,
+		'msg': msg
+	}
 
 
 ######### internal functions (not to be exposed) ##############
 
+def get_commit_redirect(main_url, storagename, batch_xml):
+	module_r = None
+	for node in batch_xml.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == 'module':
+				module_r = node
+	if module_r is None:
+		raise Exception, 'missing <module/> in <batch/>'
+	resp_r = None
+	for node in module_r.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == RESPONSE_TAG:
+				resp_r = node
+	if resp_r is None:
+		raise Exception, 'missing <response/> in <module/>'
+	fr_r = None
+	for node in resp_r.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == FUNC_RESP_TAG:
+				fr_r = node
+	if fr_r is None:
+		raise Exception, 'missing <function_response/> in <response/>'
+	rvars = {}
+	for node in fr_r.childNodes:
+		try:
+			var = parse_variable(node)
+			rvars[var.get_name()] = var
+		except:
+			pass
+
+	mapper_id = ''
+	mapper_type = ''
+	bd_path = ''
+	if 'mapper' in rvars:
+		mapper = rvars['mapper'].get_value()
+		mapper_type = mapper.getAttribute('mapper_type')
+		mapper_id = mapper.getAttribute('mapper_id')
+	if 'bd' in rvars:
+		bd = rvars['bd'].get_value()
+		bd_path = bd.getAttribute('path')
+		mapper_type = bd.getAttribute('mapper_type')
+		mapper_id = bd.getAttribute('mapper_id')
+
+	url_list = list()
+	url_list.append('%s?%s=%s' % (main_url, STONAME, storagename))
+	if mapper_type != '':
+		url_list.append('&%s=%s' % (PT_MAPPER_TYPE, mapper_type))
+	if mapper_id != '':
+		url_list.append('&%s=%s' % (PT_MAPPER_ID, mapper_id))
+	if bd_path != '':
+		url_list.append('&%s=%s' % (PT_PATH, bd_path))
+
+	if mapper_type == '':
+		url_list.append('&%s=%s' % (PAGETYPE, STORAGE))
+	elif bd_path != '':
+		url_list.append('&%s=%s' % (PAGETYPE, VIEW_BD))
+	else:
+		url_list.append('&%s=%s' % (PAGETYPE, VIEW_MAPPER))
 
-
-def get_commit_redirect(main_url,
-                        storagename,
-                        batch_xml):
-    module_r = None
-    for node in batch_xml.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == 'module':
-                module_r = node
-    if module_r is None:
-        raise Exception, 'missing <module/> in <batch/>'
-    resp_r = None
-    for node in module_r.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == RESPONSE_TAG:
-                resp_r = node
-    if resp_r is None:
-        raise Exception, 'missing <response/> in <module/>'
-    fr_r = None
-    for node in resp_r.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == FUNC_RESP_TAG:
-                fr_r = node
-    if fr_r is None:
-        raise Exception, 'missing <function_response/> in <response/>'
-    rvars = {}
-    for node in fr_r.childNodes:
-        try:
-            var = parse_variable(node)
-            rvars[var.get_name()] = var
-        except:
-            pass
-
-
-    mapper_id   = ''
-    mapper_type = ''
-    bd_path     = ''
-    if 'mapper' in rvars:
-        mapper      = rvars['mapper'].get_value()
-        mapper_type = mapper.getAttribute('mapper_type')
-        mapper_id   = mapper.getAttribute('mapper_id')
-    if 'bd' in rvars:
-        bd          = rvars['bd'].get_value()
-        bd_path     = bd.getAttribute('path')
-        mapper_type = bd.getAttribute('mapper_type')
-        mapper_id   = bd.getAttribute('mapper_id')
-
-    url_list = list()
-    url_list.append('%s?%s=%s' % (main_url, STONAME, storagename))
-    if mapper_type != '':
-        url_list.append('&%s=%s' % (PT_MAPPER_TYPE, mapper_type))
-    if mapper_id != '':
-        url_list.append('&%s=%s' % (PT_MAPPER_ID, mapper_id))
-    if bd_path != '':
-        url_list.append('&%s=%s' % (PT_PATH, bd_path))
-
-    if mapper_type == '':
-        url_list.append('&%s=%s' % (PAGETYPE, STORAGE))
-    elif bd_path != '':
-        url_list.append('&%s=%s' % (PAGETYPE, VIEW_BD))
-    else:
-        url_list.append('&%s=%s' % (PAGETYPE, VIEW_MAPPER))
-
-    return ''.join(url_list)
+	return ''.join(url_list)
 
 
 def get_bd_data_internal(session, bd_xml, mapper_xml):
-    data = {}
+	data = {}
 
-    removable, props = get_props_data_internal(session, bd_xml)
+	removable, props = get_props_data_internal(session, bd_xml)
 
-    path = bd_xml.getAttribute('path')
-    mapper_type = bd_xml.getAttribute('mapper_type')
-    mapper_id = bd_xml.getAttribute('mapper_id')
-    contents = get_content_data_internal(session, bd_xml)
-
-    pretty_mapper_type, pretty_type, dummy2 = get_pretty_mapper_info(mapper_type)
-    pretty_name = path.replace('/dev/','')
-    dummy1, icon_name, dummy2 = get_mapper_icons(mapper_type)
-    color = 'black'
-
-    size_in_units, units = bytes_to_value_units(props['size']['value'])
-
-    description = None
-    if mapper_type == MAPPER_SYS_TYPE:
-        if 'scsi_id' in props:
-            description = '%s %s, SCSI ID = %s' \
-                % (size_in_units, units, props['scsi_id']['value'])
-            icon_name = 'icon_bd_scsi.png'
-    elif mapper_type == MAPPER_VG_TYPE:
-        pretty_name = props['lvname']['value']
-        color = '#0192db'
-        if props['snapshot']['value'] == 'true':
-            icon_name = 'icon_bd_LV_snapshot.png'
-            pretty_type = 'Snapshot'
-
-    if description is None:
-        description = '%s %s' % (size_in_units, units)
-
-    if bd_xml.nodeName == BD_TEMPLATE:
-        if mapper_type == MAPPER_PT_TYPE:
-            path = 'unused_segment_%s_%s' \
-                % (props['partition_begin']['value'], props['partition_type']['value'])
-        else:
-            path = 'unused_segment'
-        pretty_type = 'New %s' % pretty_type
-        pretty_name = 'Unused Space'
-        data['new'] = True
-    else:
-        data['new'] = False
-    if mapper_type == MAPPER_VG_TYPE:
-        if props['snapshot']['value'] == 'true':
-            if data['new']:
-                contents = []
-                path = 'new_snapshot'
-                pretty_name = ''
-
-    data['pretty_mapper_type'] = pretty_mapper_type
-    data['pretty_type'] = pretty_type
-    data['pretty_name'] = pretty_name
-    data['description'] = description
-    data['props'] = props
-    data['props_ordered'] = get_ordered_props(props)
-    data['path'] = path
-    data['mapper_type'] = mapper_type
-    data['mapper_id'] = mapper_id
-    data['contents'] = contents
-    data['icon'] = icon_name
-    data['color'] = color
-    data['xml'] = bd_xml#.cloneNode(True)
-
-    actions = []
-    if removable:
-        action = {'name' : 'Remove',
-                  'msg'  : 'Are you sure you want to remove %s \\\'%s\\\'?' \
-                     % (pretty_type, pretty_name),
-                  'link' : ''}
-        actions.append(action)
-    if data['mapper_type'] == MAPPER_VG_TYPE and not data['new']:
-        nts = None
-        for node in mapper_xml.childNodes:
-            if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                if node.nodeName == MAPPER_NEW_TARGETS_TAG:
-                    nts = node
-        snap_lv = None
-        for node in nts.childNodes:
-            if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                if node.nodeName == BD_TEMPLATE:
-                    snap_lv = get_bd_data_internal(session, node, mapper_xml)
-
-        if snap_lv is not None and snap_lv['props']['clustered']['value'] != 'true':
-            if snap_lv['props']['snapshot']['value'] == 'true':
-                origs = snap_lv['props']['snapshot_origin']['value']
-                if pretty_name in origs:
-                    action = {'name' : 'Take Snapshot',
-                              'msg'  : '',
-                              'link' : './?%s=%s&%s=%s&%s=%s&%s=%s' \
-                                % (PAGETYPE, VIEW_BD, \
-                                   PT_MAPPER_ID, data['mapper_id'], \
-                                   PT_MAPPER_TYPE, data['mapper_type'], \
-                                   PT_PATH, snap_lv['path'])}
-                    actions.append(action)
-    data['actions'] = actions
-
-    need_apply_butt = mutable_props(data['props'])
-    if need_apply_butt is False:
-        if len(data['contents']) > 1:
-            need_apply_butt = True
-        elif len(data['contents']) == 1:
-            need_apply_butt = mutable_props(data['contents'][0]['props'])
-        else:
-            need_apply_butt = False
-    data['need_apply_button'] = need_apply_butt
-
-    return data
+	path = bd_xml.getAttribute('path')
+	mapper_type = bd_xml.getAttribute('mapper_type')
+	mapper_id = bd_xml.getAttribute('mapper_id')
+	contents = get_content_data_internal(session, bd_xml)
+
+	pretty_mapper_type, pretty_type, dummy2 = get_pretty_mapper_info(mapper_type)
+	pretty_name = path.replace('/dev/','')
+	dummy1, icon_name, dummy2 = get_mapper_icons(mapper_type)
+	color = 'black'
+
+	size_in_units, units = bytes_to_value_units(props['size']['value'])
+
+	description = None
+	if mapper_type == MAPPER_SYS_TYPE:
+		if 'scsi_id' in props:
+			description = '%s %s, SCSI ID = %s' \
+				% (size_in_units, units, props['scsi_id']['value'])
+			icon_name = 'icon_bd_scsi.png'
+	elif mapper_type == MAPPER_VG_TYPE:
+		pretty_name = props['lvname']['value']
+		color = '#0192db'
+		if props['snapshot']['value'] == 'true':
+			icon_name = 'icon_bd_LV_snapshot.png'
+			pretty_type = 'Snapshot'
+
+	if description is None:
+		description = '%s %s' % (size_in_units, units)
+
+	if bd_xml.nodeName == BD_TEMPLATE:
+		if mapper_type == MAPPER_PT_TYPE:
+			path = 'unused_segment_%s_%s' \
+				% (props['partition_begin']['value'], props['partition_type']['value'])
+		else:
+			path = 'unused_segment'
+		pretty_type = 'New %s' % pretty_type
+		pretty_name = 'Unused Space'
+		data['new'] = True
+	else:
+		data['new'] = False
+	if mapper_type == MAPPER_VG_TYPE:
+		if props['snapshot']['value'] == 'true':
+			if data['new']:
+				contents = []
+				path = 'new_snapshot'
+				pretty_name = ''
+
+	data['pretty_mapper_type'] = pretty_mapper_type
+	data['pretty_type'] = pretty_type
+	data['pretty_name'] = pretty_name
+	data['description'] = description
+	data['props'] = props
+	data['props_ordered'] = get_ordered_props(props)
+	data['path'] = path
+	data['mapper_type'] = mapper_type
+	data['mapper_id'] = mapper_id
+	data['contents'] = contents
+	data['icon'] = icon_name
+	data['color'] = color
+	data['xml'] = bd_xml#.cloneNode(True)
+
+	actions = []
+	if removable:
+		action = {
+			'name': 'Remove',
+			'msg': 'Are you sure you want to remove %s \\\'%s\\\'?' \
+						% (pretty_type, pretty_name),
+			'link': ''
+		}
+		actions.append(action)
+	if data['mapper_type'] == MAPPER_VG_TYPE and not data['new']:
+		nts = None
+		for node in mapper_xml.childNodes:
+			if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+				if node.nodeName == MAPPER_NEW_TARGETS_TAG:
+					nts = node
+		snap_lv = None
+		for node in nts.childNodes:
+			if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+				if node.nodeName == BD_TEMPLATE:
+					snap_lv = get_bd_data_internal(session, node, mapper_xml)
+
+		if snap_lv is not None and snap_lv['props']['clustered']['value'] != 'true':
+			if snap_lv['props']['snapshot']['value'] == 'true':
+				origs = snap_lv['props']['snapshot_origin']['value']
+				if pretty_name in origs:
+					action = {
+						'name': 'Take Snapshot',
+						'msg': '',
+						'link': './?%s=%s&%s=%s&%s=%s&%s=%s' \
+									% (PAGETYPE, VIEW_BD, \
+										PT_MAPPER_ID, data['mapper_id'], \
+										PT_MAPPER_TYPE, data['mapper_type'], \
+										PT_PATH, snap_lv['path'])
+					}
+					actions.append(action)
+	data['actions'] = actions
+
+	need_apply_butt = mutable_props(data['props'])
+	if need_apply_butt is False:
+		if len(data['contents']) > 1:
+			need_apply_butt = True
+		elif len(data['contents']) == 1:
+			need_apply_butt = mutable_props(data['contents'][0]['props'])
+		else:
+			need_apply_butt = False
+	data['need_apply_button'] = need_apply_butt
 
+	return data
 
 def get_props_data_internal(session, xml_tag):
-    data = {}
-    removable = False
-
+	data = {}
+	removable = False
 
-    props_xml = None
-    for node in xml_tag.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == PROPS_TAG:
-                props_xml = node
-    var_xmls = {}
-    for node in props_xml.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == VARIABLE_TAG:
-                var_xmls[node.getAttribute('name')] = node
-    removable = False
-    for name in var_xmls:
-        var = var_xmls[name]
-        mutable = var.getAttribute('mutable') == 'true'
-        var_type = var.getAttribute('type')
-        value = var.getAttribute('value')
-
-        d_units = ''
-        if name in ['size', 'extent_size', 'block_size', 'size_free', 'partition_begin']:
-            d_units = 'bytes'
-        if 'percent' in name:
-            d_units = '%'
-
-        validation_data = {}
-        if var_type == VARIABLE_TYPE_INT:
-            d_type = 'int'
-            d_value = value
-            min_val  = var.getAttribute('min')
-            max_val  = var.getAttribute('max')
-            step = var.getAttribute('step')
-            validation_data['min']  = str(min_val)
-            validation_data['max']  = str(max_val)
-            validation_data['step'] = str(step)
-        elif var_type == VARIABLE_TYPE_STRING:
-            d_type = 'text'
-            d_value = value
-            validation_data['min_length'] = var.getAttribute('min_length')
-            validation_data['max_length'] = var.getAttribute('max_length')
-            validation_data['illegal_chars'] = var.getAttribute('illegal_chars').replace('\'', '\\\'').replace('<', '<').replace('>', '>').replace('"', '\\\"').replace('&', '&')
-            validation_data['reserved_words'] = var.getAttribute('reserved_words')
-        elif var_type == VARIABLE_TYPE_INT_SEL or var_type == VARIABLE_TYPE_STRING_SEL:
-            d_type = 'select'
-            d_value = [value]
-            for node in var.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == VARIABLE_TYPE_LISTENTRY:
-                        val = node.getAttribute('value')
-                        if val not in d_value:
-                            d_value.append(val)
-        elif var_type == VARIABLE_TYPE_BOOL:
-            d_type = 'select'
-            d_value = [value]
-            if value == 'true':
-                d_value.append('false')
-            else:
-                d_value.append('true')
-        elif var_type == VARIABLE_TYPE_LIST_INT or var_type == VARIABLE_TYPE_LIST_STR:
-            d_type = 'label'
-            d_value = ''
-            d_val_list = list()
-            for node in var.childNodes:
-                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                    if node.nodeName == VARIABLE_TYPE_LISTENTRY:
-                        d_val_list.append(node.getAttribute('value'))
-                        d_val_list.append(', ')
-            d_value = ''.join(d_val_list)
-            if d_value != '':
-                d_value = d_value[:len(d_value)-2]
-        elif var_type == 'hidden':
-            d_type = 'hidden'
-            d_value = str(value)
-        else:
-            d_type = 'label'
-            d_value = value
-
-        if not mutable and d_type != 'label' and d_type != 'hidden':
-            d_type = 'label'
-            d_value = str(value)
-
-        hidden = False
-        if var_type == 'hidden' or name in ['partition_begin', 'snapshot']:
-            hidden = True
-
-        if name == 'removable':
-            removable = value == 'true'
-        elif name == 'path':
-            pass
-        else:
-            data[name] = {'name'        : name,
-                          'pretty_name' : get_pretty_prop_name(name),
-                          'type'        : d_type,
-                          'value'       : d_value,
-                          'units'       : d_units,
-                          'validation'  : validation_data,
-                          'hidden'      : hidden}
+	props_xml = None
+	for node in xml_tag.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == PROPS_TAG:
+				props_xml = node
+
+	var_xmls = {}
+	for node in props_xml.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == VARIABLE_TAG:
+				var_xmls[node.getAttribute('name')] = node
+
+	removable = False
+	for name in var_xmls:
+		var = var_xmls[name]
+		mutable = var.getAttribute('mutable') == 'true'
+		var_type = var.getAttribute('type')
+		value = var.getAttribute('value')
+
+		d_units = ''
+		if name in ['size', 'extent_size', 'block_size', 'size_free', 'partition_begin']:
+			d_units = 'bytes'
+		if 'percent' in name:
+			d_units = '%'
+
+		validation_data = {}
+		if var_type == VARIABLE_TYPE_INT:
+			d_type = 'int'
+			d_value = value
+			min_val = var.getAttribute('min')
+			max_val = var.getAttribute('max')
+			step = var.getAttribute('step')
+			validation_data['min'] = str(min_val)
+			validation_data['max'] = str(max_val)
+			validation_data['step'] = str(step)
+		elif var_type == VARIABLE_TYPE_STRING:
+			d_type = 'text'
+			d_value = value
+			validation_data['min_length'] = var.getAttribute('min_length')
+			validation_data['max_length'] = var.getAttribute('max_length')
+			validation_data['illegal_chars'] = var.getAttribute('illegal_chars').replace('\'', '\\\'').replace('<', '<').replace('>', '>').replace('"', '\\\"').replace('&', '&')
+			validation_data['reserved_words'] = var.getAttribute('reserved_words')
+		elif var_type == VARIABLE_TYPE_INT_SEL or var_type == VARIABLE_TYPE_STRING_SEL:
+			d_type = 'select'
+			d_value = [value]
+			for node in var.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == VARIABLE_TYPE_LISTENTRY:
+						val = node.getAttribute('value')
+						if val not in d_value:
+							d_value.append(val)
+		elif var_type == VARIABLE_TYPE_BOOL:
+			d_type = 'select'
+			d_value = [value]
+			if value == 'true':
+				d_value.append('false')
+			else:
+				d_value.append('true')
+		elif var_type == VARIABLE_TYPE_LIST_INT or var_type == VARIABLE_TYPE_LIST_STR:
+			d_type = 'label'
+			d_value = ''
+			d_val_list = list()
+			for node in var.childNodes:
+				if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+					if node.nodeName == VARIABLE_TYPE_LISTENTRY:
+						d_val_list.append(node.getAttribute('value'))
+						d_val_list.append(', ')
+			d_value = ''.join(d_val_list)
+			if d_value != '':
+				d_value = d_value[:len(d_value)-2]
+		elif var_type == 'hidden':
+			d_type = 'hidden'
+			d_value = str(value)
+		else:
+			d_type = 'label'
+			d_value = value
+
+		if not mutable and d_type != 'label' and d_type != 'hidden':
+			d_type = 'label'
+			d_value = str(value)
+
+		hidden = False
+		if var_type == 'hidden' or name in ['partition_begin', 'snapshot']:
+			hidden = True
+
+		if name == 'removable':
+			removable = value == 'true'
+		elif name == 'path':
+			pass
+		else:
+			data[name] = {
+				'name': name,
+				'pretty_name': get_pretty_prop_name(name),
+				'type': d_type,
+				'value': d_value,
+				'units': d_units,
+				'validation': validation_data,
+				'hidden': hidden
+			}
 
-    return (removable, data)
+	return (removable, data)
 
 
 def get_ordered_props(props):
-    names   = []
-    sizes   = []
-    mounts  = []
-    min_max = []
-    uuids   = []
-    rest    = []
-    for prop_name in props:
-        prop = props[prop_name]
-        # names
-        if 'name' in prop_name or 'label' in prop_name or 'vendor' == prop_name or 'model' == prop_name:
-            names.append(prop)
-        # sizes
-        elif 'size' in prop_name or 'extents' in prop_name or 'percent' in prop_name:
-            sizes.append(prop)
-        # mounts
-        elif 'mount' in prop_name or 'fstab' in prop_name:
-            mounts.append(prop)
-        # min_max
-        elif 'min' in prop_name or 'max' in prop_name:
-            min_max.append(prop)
-        elif 'uuid' in prop_name:
-            uuids.append(prop)
-        else:
-            rest.append(prop)
-
-    ordered = []
-    for prop in names:
-        ordered.append(prop)
-    for prop in sizes:
-        ordered.append(prop)
-    for prop in mounts:
-        ordered.append(prop)
-    for prop in min_max:
-        ordered.append(prop)
-    for prop in rest:
-        ordered.append(prop)
-    for prop in uuids:
-        ordered.append(prop)
-    return ordered
+	names = []
+	sizes = []
+	mounts = []
+	min_max = []
+	uuids = []
+	rest = []
+
+	for prop_name in props:
+		prop = props[prop_name]
+		# names
+		if 'name' in prop_name or 'label' in prop_name or 'vendor' == prop_name or 'model' == prop_name:
+			names.append(prop)
+		# sizes
+		elif 'size' in prop_name or 'extents' in prop_name or 'percent' in prop_name:
+			sizes.append(prop)
+		# mounts
+		elif 'mount' in prop_name or 'fstab' in prop_name:
+			mounts.append(prop)
+		# min_max
+		elif 'min' in prop_name or 'max' in prop_name:
+			min_max.append(prop)
+		elif 'uuid' in prop_name:
+			uuids.append(prop)
+		else:
+			rest.append(prop)
+
+	ordered = []
+	for prop in names:
+		ordered.append(prop)
+	for prop in sizes:
+		ordered.append(prop)
+	for prop in mounts:
+		ordered.append(prop)
+	for prop in min_max:
+		ordered.append(prop)
+	for prop in rest:
+		ordered.append(prop)
+	for prop in uuids:
+		ordered.append(prop)
+	return ordered
 
 
 
 def mutable_props(props):
-    for name in props:
-        prop_type = props[name]['type']
-        if prop_type == 'int' or prop_type == 'text' or prop_type == 'select':
-            return True
-    return False
+	for name in props:
+		prop_type = props[name]['type']
+		if prop_type == 'int' or prop_type == 'text' or prop_type == 'select':
+			return True
+	return False
 
 
 
 def get_content_data_internal(session, bd_xml):
-    c_xml = None
-    for node in bd_xml.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == CONTENT_TYPE:
-                c_xml = node
-                break
-    if c_xml is None:
-        return {}
-
-    a_xmls = []
-    for node in c_xml.childNodes:
-        if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-            if node.nodeName == "available_contents":
-                a_conts = node
-                for node in a_conts.childNodes:
-                    if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-                        if node.nodeName == "content_template":
-                            a_xmls.append(node)
-                break
-
-    current = {}
-    removable, props = get_props_data_internal(session, c_xml)
-    current['props'] = props
-    name, content_id = get_content_name_id(c_xml)
-    current['name'] = name
-    current['id'] = content_id
-    current['xml'] = c_xml#.cloneNode(True)
-
-    data = [current]
-    for a_xml in a_xmls:
-        available = {}
-        removable, props = get_props_data_internal(session, a_xml)
-        available['props'] = props
-        name, content_id = get_content_name_id(a_xml)
-        available['name'] = name
-        available['id'] = content_id
-        available['xml'] = a_xml#.cloneNode(True)
-
-        data.append(available)
-
-    for d in data:
-        old_props = d['props']
-        new_props = {}
-        for name in old_props:
-            new_name = 'content_variable_%s_%s' % (d['id'], name)
-            new_props[new_name] = old_props[name]
-            new_props[new_name]['name'] = new_name
-        d['props'] = new_props
-        d['props_ordered'] = get_ordered_props(new_props)
-        d['is_source'] = False
-
-        # content's color and icon
-        color = 'black'
-        icon_name = ''
-        content_type = d['xml'].getAttribute('type')
-        if content_type == 'filesystem':
-            icon_name = get_fs_icon(d['xml'].getAttribute('fs_type'))
-        elif content_type == 'mapper_source':
-            mapper_type = d['xml'].getAttribute('mapper_type')
-            mapper_id = d['xml'].getAttribute('mapper_id')
-            pretty_mapper_type, dummy1, dummy2 = get_pretty_mapper_info(mapper_type)
-            dummy1, dummy2, icon_name = get_mapper_icons(mapper_type)
-            if mapper_type == MAPPER_VG_TYPE:
-                color = '#a43737'
-            d['is_source'] = True
-            d['mapper_type'] = mapper_type
-            d['mapper_id'] = mapper_id
-            d['pretty_mapper_type'] = pretty_mapper_type
-        elif content_type == 'none':
-            pass
-        elif content_type == 'hidden':
-            pass
+	c_xml = None
+	for node in bd_xml.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == CONTENT_TYPE:
+				c_xml = node
+				break
+	if c_xml is None:
+		return {}
+
+	a_xmls = []
+	for node in c_xml.childNodes:
+		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+			if node.nodeName == "available_contents":
+				a_conts = node
+				for node in a_conts.childNodes:
+					if node.nodeType == xml.dom.Node.ELEMENT_NODE:
+						if node.nodeName == "content_template":
+							a_xmls.append(node)
+				break
+
+	current = {}
+	removable, props = get_props_data_internal(session, c_xml)
+	current['props'] = props
+	name, content_id = get_content_name_id(c_xml)
+	current['name'] = name
+	current['id'] = content_id
+	current['xml'] = c_xml#.cloneNode(True)
+
+	data = [current]
+	for a_xml in a_xmls:
+		available = {}
+		removable, props = get_props_data_internal(session, a_xml)
+		available['props'] = props
+		name, content_id = get_content_name_id(a_xml)
+		available['name'] = name
+		available['id'] = content_id
+		available['xml'] = a_xml#.cloneNode(True)
+
+		data.append(available)
+
+	for d in data:
+		old_props = d['props']
+		new_props = {}
+		for name in old_props:
+			new_name = 'content_variable_%s_%s' % (d['id'], name)
+			new_props[new_name] = old_props[name]
+			new_props[new_name]['name'] = new_name
+		d['props'] = new_props
+		d['props_ordered'] = get_ordered_props(new_props)
+		d['is_source'] = False
+
+		# content's color and icon
+		color = 'black'
+		icon_name = ''
+		content_type = d['xml'].getAttribute('type')
+		if content_type == 'filesystem':
+			icon_name = get_fs_icon(d['xml'].getAttribute('fs_type'))
+		elif content_type == 'mapper_source':
+			mapper_type = d['xml'].getAttribute('mapper_type')
+			mapper_id = d['xml'].getAttribute('mapper_id')
+			pretty_mapper_type, dummy1, dummy2 = get_pretty_mapper_info(mapper_type)
+			dummy1, dummy2, icon_name = get_mapper_icons(mapper_type)
+			if mapper_type == MAPPER_VG_TYPE:
+				color = '#a43737'
+			d['is_source'] = True
+			d['mapper_type'] = mapper_type
+			d['mapper_id'] = mapper_id
+			d['pretty_mapper_type'] = pretty_mapper_type
+		elif content_type == 'none':
+			pass
+		elif content_type == 'hidden':
+			pass
 
-        d['color'] = color
-        d['icon'] = icon_name
+		d['color'] = color
+		d['icon'] = icon_name
 
-    return data
+	return data
 
 
 
 def get_content_name_id(c_xml):
-    name = 'Unknown type'
-    content_id = c_xml.getAttribute('type')
-    if content_id == CONTENT_FS_TYPE:
-        fs_type = c_xml.getAttribute('fs_type')
-        content_id = '%s_%s' % (content_id, fs_type)
-        name = get_pretty_fs_name(fs_type)
-    elif content_id == CONTENT_NONE_TYPE:
-        name = 'Empty'
-    elif content_id == CONTENT_MS_TYPE:
-        mapper_type = c_xml.getAttribute('mapper_type')
-        mapper_id = c_xml.getAttribute('mapper_id')
-        content_id = '%s_%s_%s' % (content_id, mapper_type, mapper_id.replace(':', '__colon__'))
-        if mapper_type == MAPPER_SYS_TYPE:
-            pass
-        elif mapper_type == MAPPER_VG_TYPE:
-            name = 'Physical Volume'
-        elif mapper_type == MAPPER_PT_TYPE:
-            name = 'Partition Table'
-        elif mapper_type == MAPPER_MDRAID_TYPE:
-            name = 'Software RAID Disk'
-        elif mapper_type == MAPPER_ATARAID_TYPE:
-            name = 'ATA-RAID Disk'
-        elif mapper_type == MAPPER_MULTIPATH_TYPE:
-            name = 'Multipath\'s Path'
-        elif mapper_type == MAPPER_CRYPTO_TYPE:
-            name = 'Encrypted Device'
-        elif mapper_type == MAPPER_iSCSI_TYPE:
-            pass
-        else:
-            name = 'Source of %s' % mapper_type
-    elif content_id == CONTENT_HIDDEN_TYPE:
-        name = 'Extended Partition'
-    else:
-        name = 'Unknown type'
+	name = 'Unknown type'
+	content_id = c_xml.getAttribute('type')
+	if content_id == CONTENT_FS_TYPE:
+		fs_type = c_xml.getAttribute('fs_type')
+		content_id = '%s_%s' % (content_id, fs_type)
+		name = get_pretty_fs_name(fs_type)
+	elif content_id == CONTENT_NONE_TYPE:
+		name = 'Empty'
+	elif content_id == CONTENT_MS_TYPE:
+		mapper_type = c_xml.getAttribute('mapper_type')
+		mapper_id = c_xml.getAttribute('mapper_id')
+		content_id = '%s_%s_%s' % (content_id, mapper_type, mapper_id.replace(':', '__colon__'))
+		if mapper_type == MAPPER_SYS_TYPE:
+			pass
+		elif mapper_type == MAPPER_VG_TYPE:
+			name = 'Physical Volume'
+		elif mapper_type == MAPPER_PT_TYPE:
+			name = 'Partition Table'
+		elif mapper_type == MAPPER_MDRAID_TYPE:
+			name = 'Software RAID Disk'
+		elif mapper_type == MAPPER_ATARAID_TYPE:
+			name = 'ATA-RAID Disk'
+		elif mapper_type == MAPPER_MULTIPATH_TYPE:
+			name = 'Multipath\'s Path'
+		elif mapper_type == MAPPER_CRYPTO_TYPE:
+			name = 'Encrypted Device'
+		elif mapper_type == MAPPER_iSCSI_TYPE:
+			pass
+		else:
+			name = 'Source of %s' % mapper_type
+	elif content_id == CONTENT_HIDDEN_TYPE:
+		name = 'Extended Partition'
+	else:
+		name = 'Unknown type'
 
-    return name, content_id
+	return name, content_id
 
 
 
 def group_systems_by_cluster(self, allowed_systems, from_cache=False):
-    ss = get_systems_statuses(self, allowed_systems, from_cache)
-    clusters = {}
-    bad_list = []
-    for s in ss:
-        if s['authed']:
-            cluname = s['cluname']
-            if cluname not in clusters:
-                clusters[cluname] = []
-            clusters[cluname].append(s)
-        else:
-            bad_list.append(s)
-    clu_list = []
-    nonclu_list = []
-    for cluname in clusters:
-        if cluname == '':
-            nonclu_list = clusters[cluname]
-        else:
-            cl = {'name'  : cluname,
-                  'alias' : clusters[cluname][0]['clualias'],
-                  'nodes' : clusters[cluname]}
-            clu_list.append(cl)
-
-    ret = [nonclu_list, clu_list, bad_list]
-
-    return ret
-
-
-
-
-def get_mappings_info(self,
-                      mapper_data,
-                      length):
-    # highlights
-    high_list = {}
-
-    # upper cyl
-    upper_cyl = {'offset'     : 0,
-                 'cyls'       : [],
-                 'highs'      : [],
-                 'js'         : [],
-                 'color'      : 'blue',
-                 'color_css'  : '#0192db',
-                 'description': mapper_data['pretty_targets_name']}
-    if mapper_data['mapper_type'] == MAPPER_PT_TYPE:
-        upper_cyl['description'] = 'Physical %s' % upper_cyl['description']
-
-    offset = 0
-    for t in mapper_data['targets_all']:
-        if t['mapper_type'] == MAPPER_PT_TYPE:
-            if t['props']['partition_type']['value'] == 'logical':
-                continue
-        data = {}
-        data['bd']        = t
-        data['id']        = t['path']
-        beg = offset
-        end = beg + int(t['props']['size']['value'])
-        data['beg']       = beg
-        data['end']       = end
-        data['color']     = 'blue'
-        data['color_css'] = '#0192db'
-        if mapper_data['mapper_type'] == MAPPER_PT_TYPE:
-            if t['props']['partition_type']['value'] == 'extended' and not t['new']:
-                data['color']     = 'black'
-                data['color_css'] = 'black'
-        upper_cyl['cyls'].append(data)
-        offset = end
-
-    # scale ranges
-    for d in upper_cyl['cyls']:
-        d['beg'] = d['beg'] * length / offset
-        d['end'] = d['end'] * length / offset - 1
-
-    # build highlights
-    for d in upper_cyl['cyls']:
-        h_id = '%s_selected' % d['id']
-        beg = d['beg']
-        end = d['end']
-        upper_cyl['highs'].append({'beg'  : beg,
-                                   'end'  : end,
-                                   'id'   : h_id,
-                                   'type' : 'select'})
-        upper_cyl['js'].append([d['id'],
-                                [beg, end],
-                                d['bd']['pretty_name']])
-        high_list[d['id']] = [h_id]
-
-        # snapshots
-        bd = d['bd']
-        if bd['mapper_type'] == MAPPER_VG_TYPE and not bd['new']:
-            if 'origin' in bd:
-                # snapshot
-                snap_id = '%s_snapshot' % bd['path']
-                upper_cyl['highs'].append({'beg'  : beg,
-                                           'end'  : end,
-                                           'id'   : snap_id,
-                                           'type' : 'snapshot'})
-                orig = bd['origin']
-                high_list[d['id']].append('%s_origin' % orig['path'])
-                high_list[d['id']].append(snap_id)
-            if 'snapshots' in bd:
-                # origin
-                upper_cyl['highs'].append({'beg'  : beg,
-                                           'end'  : end,
-                                           'id'   : '%s_origin' % bd['path'],
-                                           'type' : 'snapshot-origin'})
-                for snap in bd['snapshots']:
-                    high_list[d['id']].append('%s_snapshot' % snap['path'])
-
-
-
-    upper_cyl['js'] = str(upper_cyl['js']).replace('L,', ',').replace('L]', ']').replace('u\'', '\'').replace('L]', ']')
-
-    # lower cylinder
-    lower_cyl = {'offset'     : 0,
-                 'cyls'       : [],
-                 'highs'      : [],
-                 'js'         : [],
-                 'color'      : 'red',
-                 'color_css'  : '#a43737',
-                 'description': mapper_data['pretty_sources_name']}
-
-    offset = 0
-    for t in mapper_data['sources']:
-        data = {}
-        data['bd']        = t
-        data['id']        = t['path']
-        beg = offset
-        end = beg + int(t['props']['size']['value'])
-        data['beg']       = beg
-        data['end']       = end
-        data['color']     = 'red'
-        data['color_css'] = '#a43737'
-        lower_cyl['cyls'].append(data)
-        offset = end
-
-    if mapper_data['mapper_type'] == MAPPER_PT_TYPE:
-        lower_cyl['description'] = 'Logical %s' % mapper_data['pretty_targets_name']
-        lower_cyl['cyls']        = []
-        lower_cyl['color']       = 'blue'
-        lower_cyl['color_css']   = '#0192db'
-        lower_cyl['offset']      = 9999999999999999999999999
-
-        offset = 0
-        for t in mapper_data['targets_all']:
-            if t['props']['partition_type']['value'] != 'logical':
-                continue
-            part_beg = int(t['props']['partition_begin']['value'])
-            if part_beg < lower_cyl['offset']:
-                lower_cyl['offset'] = part_beg
-            data = {}
-            data['bd']        = t
-            data['id']        = t['path']
-            beg = offset
-            end = beg + int(t['props']['size']['value'])
-            data['beg']       = beg
-            data['end']       = end
-            data['color']     = 'blue'
-            data['color_css'] = '#0192db'
-            lower_cyl['cyls'].append(data)
-            offset = end
-
-
-    # scale ranges
-    length_in_bytes = 0
-    for t in mapper_data['sources']:
-        length_in_bytes += int(t['props']['size']['value'])
-    ppb = (length * 1.0) / max(0.00001, length_in_bytes)  # pixels per byte
-    lower_cyl['offset'] = int(lower_cyl['offset'] * ppb)
-    for d in lower_cyl['cyls']:
-        d['beg'] = int(d['beg'] * ppb)
-        d['end'] = int(d['end'] * ppb - 1)
-
-
-
-    # build highlights
-    for d in lower_cyl['cyls']:
-        h_id = '%s_selected' % d['id']
-        beg = d['beg']
-        end = d['end']
-        lower_cyl['highs'].append({'beg'  : beg,
-                                   'end'  : end,
-                                   'id'   : h_id,
-                                   'type' : 'select'})
-        lower_cyl['js'].append([d['id'],
-                                [beg, end],
-                                d['bd']['pretty_name']])
-        high_list[d['id']] = [h_id]
-    lower_cyl['js'] = str(lower_cyl['js']).replace('L,', ',').replace('L]', ']').replace('u\'', '\'').replace('L]', ']')
-
-    # transform list of highlights
-    high_list_js = [[mapper_data['mapper_id'], []]]
-    for hl_id in high_list:
-        high_list_js.append([hl_id, high_list[hl_id]])
-    high_list_js = str(high_list_js).replace('L,', ',').replace('L]', ']').replace('u\'', '\'').replace('L]', ']')
-
-    # put everything together
-    ret = {}
-    ret['mapper']         = mapper_data
-    ret['upper_cyl']      = upper_cyl
-    ret['lower_cyl']      = lower_cyl
-    ret['js']             = high_list_js
-
-    return ret
+	ss = get_systems_statuses(self, allowed_systems, from_cache)
+	clusters = {}
+	bad_list = []
+	for s in ss:
+		if s['authed']:
+			cluname = s['cluname']
+			if cluname not in clusters:
+				clusters[cluname] = []
+			clusters[cluname].append(s)
+		else:
+			bad_list.append(s)
+	clu_list = []
+	nonclu_list = []
+	for cluname in clusters:
+		if cluname == '':
+			nonclu_list = clusters[cluname]
+		else:
+			cl = {
+				'name': cluname,
+				'alias': clusters[cluname][0]['clualias'],
+				'nodes': clusters[cluname]
+			}
+			clu_list.append(cl)
+
+	ret = [ nonclu_list, clu_list, bad_list ]
+	return ret
+
+def get_mappings_info(self, mapper_data, length):
+	# highlights
+	high_list = {}
+
+	# upper cyl
+	upper_cyl = {
+		'offset': 0,
+		'cyls': [],
+		'highs': [],
+		'js': [],
+		'color': 'blue',
+		'color_css': '#0192db',
+		'description': mapper_data['pretty_targets_name']
+	}
+
+	if mapper_data['mapper_type'] == MAPPER_PT_TYPE:
+		upper_cyl['description'] = 'Physical %s' % upper_cyl['description']
+
+	offset = 0
+	for t in mapper_data['targets_all']:
+		if t['mapper_type'] == MAPPER_PT_TYPE:
+			if t['props']['partition_type']['value'] == 'logical':
+				continue
+
+		data = {}
+		data['bd'] = t
+		data['id'] = t['path']
+		beg = offset
+		end = beg + int(t['props']['size']['value'])
+		data['beg'] = beg
+		data['end'] = end
+		data['color'] = 'blue'
+		data['color_css'] = '#0192db'
+
+		if mapper_data['mapper_type'] == MAPPER_PT_TYPE:
+			if t['props']['partition_type']['value'] == 'extended' and not t['new']:
+				data['color'] = 'black'
+				data['color_css'] = 'black'
+		upper_cyl['cyls'].append(data)
+		offset = end
+
+	# scale ranges
+	for d in upper_cyl['cyls']:
+		d['beg'] = d['beg'] * length / offset
+		d['end'] = d['end'] * length / offset - 1
+
+	# build highlights
+	for d in upper_cyl['cyls']:
+		h_id = '%s_selected' % d['id']
+		beg = d['beg']
+		end = d['end']
+		upper_cyl['highs'].append({
+			'beg': beg,
+			'end': end,
+			'id': h_id,
+			'type': 'select'
+		})
+
+		upper_cyl['js'].append([d['id'], [beg, end], d['bd']['pretty_name']])
+		high_list[d['id']] = [h_id]
+
+		# snapshots
+		bd = d['bd']
+		if bd['mapper_type'] == MAPPER_VG_TYPE and not bd['new']:
+			if 'origin' in bd:
+				# snapshot
+				snap_id = '%s_snapshot' % bd['path']
+				upper_cyl['highs'].append({
+					'beg': beg,
+					'end': end,
+					'id': snap_id,
+					'type': 'snapshot'
+				})
+				orig = bd['origin']
+				high_list[d['id']].append('%s_origin' % orig['path'])
+				high_list[d['id']].append(snap_id)
+			if 'snapshots' in bd:
+				# origin
+				upper_cyl['highs'].append({
+					'beg': beg,
+					'end': end,
+					'id': '%s_origin' % bd['path'],
+					'type': 'snapshot-origin'
+				})
+				for snap in bd['snapshots']:
+					high_list[d['id']].append('%s_snapshot' % snap['path'])
+
+	upper_cyl['js'] = str(upper_cyl['js']).replace('L,', ',').replace('L]', ']').replace('u\'', '\'').replace('L]', ']')
+
+	# lower cylinder
+	lower_cyl = {
+		'offset': 0,
+		'cyls': [],
+		'highs': [],
+		'js': [],
+		'color': 'red',
+		'color_css': '#a43737',
+		'description': mapper_data['pretty_sources_name']
+	}
+
+	offset = 0
+	for t in mapper_data['sources']:
+		data = {}
+		data['bd'] = t
+		data['id'] = t['path']
+		beg = offset
+		end = beg + int(t['props']['size']['value'])
+		data['beg'] = beg
+		data['end'] = end
+		data['color'] = 'red'
+		data['color_css'] = '#a43737'
+		lower_cyl['cyls'].append(data)
+		offset = end
+
+	if mapper_data['mapper_type'] == MAPPER_PT_TYPE:
+		lower_cyl['description'] = 'Logical %s' % mapper_data['pretty_targets_name']
+		lower_cyl['cyls'] = []
+		lower_cyl['color'] = 'blue'
+		lower_cyl['color_css'] = '#0192db'
+		lower_cyl['offset'] = 9999999999999999999999999
+
+		offset = 0
+		for t in mapper_data['targets_all']:
+			if t['props']['partition_type']['value'] != 'logical':
+				continue
+			part_beg = int(t['props']['partition_begin']['value'])
+			if part_beg < lower_cyl['offset']:
+				lower_cyl['offset'] = part_beg
+			data = {}
+			data['bd'] = t
+			data['id'] = t['path']
+			beg = offset
+			end = beg + int(t['props']['size']['value'])
+			data['beg'] = beg
+			data['end'] = end
+			data['color'] = 'blue'
+			data['color_css'] = '#0192db'
+			lower_cyl['cyls'].append(data)
+			offset = end
+
+
+	# scale ranges
+	length_in_bytes = 0
+	for t in mapper_data['sources']:
+		length_in_bytes += int(t['props']['size']['value'])
+	ppb = (length * 1.0) / max(0.00001, length_in_bytes) # pixels per byte
+	lower_cyl['offset'] = int(lower_cyl['offset'] * ppb)
+	for d in lower_cyl['cyls']:
+		d['beg'] = int(d['beg'] * ppb)
+		d['end'] = int(d['end'] * ppb - 1)
+
+
+
+	# build highlights
+	for d in lower_cyl['cyls']:
+		h_id = '%s_selected' % d['id']
+		beg = d['beg']
+		end = d['end']
+		lower_cyl['highs'].append({
+			'beg': beg,
+			'end': end,
+			'id': h_id,
+			'type': 'select'
+		})
+		lower_cyl['js'].append([d['id'],
+								[beg, end],
+								d['bd']['pretty_name']])
+		high_list[d['id']] = [h_id]
+	lower_cyl['js'] = str(lower_cyl['js']).replace('L,', ',').replace('L]', ']').replace('u\'', '\'').replace('L]', ']')
+
+	# transform list of highlights
+	high_list_js = [[mapper_data['mapper_id'], []]]
+	for hl_id in high_list:
+		high_list_js.append([hl_id, high_list[hl_id]])
+	high_list_js = str(high_list_js).replace('L,', ',').replace('L]', ']').replace('u\'', '\'').replace('L]', ']')
+
+	# put everything together
+	ret = {}
+	ret['mapper'] = mapper_data
+	ret['upper_cyl'] = upper_cyl
+	ret['lower_cyl'] = lower_cyl
+	ret['js'] = high_list_js
+	return ret
--- conga/luci/site/luci/Extensions/storage_adapters.py	2007/06/27 08:14:13	1.11
+++ conga/luci/site/luci/Extensions/storage_adapters.py	2007/09/24 19:48:34	1.12
@@ -18,362 +18,291 @@
 from StorageReport import invalidate_storage_report
 
 def createStorageChooser(self, request, systems):
-  dummynode = {}
-
-  #First, see if a storage system is chosen, then
-  #check that the current user can access that system
-  stoname = None
-  try:
-    stoname = request[STONAME]
-  except KeyError, e:
-    stoname = ""
-
-  try:
-    url = request['URL']
-  except KeyError, e:
-    url = "."
-
-  if stoname and request.has_key('reprobe_storage'):
-    try:
-      invalidate_storage_report(request.SESSION, stoname)
-      redirect_url = '%s?%s' % (request['ACTUAL_URL'], request['QUERY_STRING'])
-      redirect_url = redirect_url.replace('&reprobe_storage=true', '')
-      request.RESPONSE.redirect(redirect_url)
-    except:
-      pass
-
-  try:
-    pagetype = request[PAGETYPE]
-  except KeyError, e:
-    pagetype = "0"
-
-  sdata = {}
-  sdata['Title'] = "System List"
-  sdata['cfg_type'] = "storages"
-  sdata['absolute_url'] = "%s?pagetype=%s" % (url, STORAGESYS)
-  sdata['Description'] = "Systems available for storage configuration"
-  if pagetype == STORAGESYS or pagetype == '0':
-    sdata['currentItem'] = True
-  else:
-    sdata['currentItem'] = False
-  if pagetype == STORAGESYS or pagetype == '0':
-    sdata['show_children'] = True
-  else:
-    sdata['show_children'] = False
-
-
-  syslist = list()
-  if sdata['show_children']:
-    #display_clusters = True
-    display_clusters = False
-    if display_clusters:
-      sorted_data = self.group_systems_by_cluster(systems, from_cache=False)
-      for sdl in sorted_data[:2]:
-        for data in sdl:
-          createStorageChooser_inner(url,
-                                     pagetype,
-                                     stoname,
-                                     data,
-                                     syslist)
-    else:
-      sorted_data = get_systems_statuses(self, systems, from_cache=False)
-      for data in sorted_data:
-        createStorageChooser_inner(url,
-                                   pagetype,
-                                   stoname,
-                                   data,
-                                   syslist)
-  sdata['children'] = syslist
-
-  mylist = list()
-  mylist.append(sdata)
-  #mylist.append(sadd)
-  #mylist.append(scfg)
-  dummynode['children'] = mylist
-
-  return dummynode
-
-
-def createStorageChooser_inner(url,
-                               pagetype,
-                               stoname,
-                               system_data,
-                               syslist):
-  ssys = {}
-  if 'nodes' in system_data:
-    title = system_data['name']
-    if system_data['alias'] != '':
-      title = '%s (%s)' % (system_data['alias'], title)
-    ssys['Title'] = 'Cluster %s' % title
-    ssys['cfg_type'] = "storage"
-    ssys['absolute_url'] = '%s?%s=%s&%s=%s' \
-      % (url, PAGETYPE, CLUSTER_STORAGE, CLUNAME, system_data['name'])
-    ssys['Description'] = "Configure shared storage of cluster %s" % title
-    ssys['currentItem'] = False
-    ssys['show_children'] = True
-    kids = []
-    for node in system_data['nodes']:
-      createStorageChooser_inner(url,
-                                 pagetype,
-                                 stoname,
-                                 node,
-                                 kids)
-    ssys['children'] = kids
-  else:
-    if system_data['authed'] is False:
-      return
-    ssys['Title'] = system_data['hostname']
-    ssys['cfg_type'] = "storage"
-    ssys['absolute_url'] = '%s?%s=%s&%s=%s' \
-      % (url, PAGETYPE, STORAGE, STONAME, system_data['hostname'])
-    ssys['Description'] = "Configure storage on %s" % system_data['hostname']
-
-    if pagetype == STORAGE:
-      if stoname == system_data['hostname']:
-        ssys['currentItem'] = True
-      else:
-        ssys['currentItem'] = False
-    else:
-      ssys['currentItem'] = False
-  syslist.append(ssys)
-  return
-
+	dummynode = {}
 
+	# First, see if a storage system is chosen, then
+	# check that the current user can access that system
+	stoname = request.get(STONAME) or ''
+	url = request.get('URL') or '.'
+	pagetype = request.get(PAGETYPE) or '0'
+
+	try:
+		if stoname and request.has_key('reprobe_storage'):
+			invalidate_storage_report(request.SESSION, stoname)
+			redirect_url = '%s?%s' % (request['ACTUAL_URL'], request['QUERY_STRING'])
+			redirect_url = redirect_url.replace('&reprobe_storage=true', '')
+			request.RESPONSE.redirect(redirect_url)
+	except:
+		pass
+
+	sdata = {}
+	sdata['Title'] = 'System List'
+	sdata['cfg_type'] = 'storages'
+	sdata['absolute_url'] = '%s?pagetype=%s' % (url, STORAGESYS)
+	sdata['Description'] = 'Systems available for storage configuration'
+
+	if pagetype == STORAGESYS or pagetype == '0':
+		sdata['show_children'] = True
+		sdata['currentItem'] = True
+	else:
+		sdata['currentItem'] = False
+		sdata['show_children'] = False
+
+	syslist = list()
+	if sdata['show_children']:
+		#display_clusters = True
+		display_clusters = False
+		if display_clusters:
+			sorted_data = self.group_systems_by_cluster(systems, from_cache=False)
+			for sdl in sorted_data[:2]:
+				for data in sdl:
+					createStorageChooser_inner(url, pagetype, stoname, data, syslist)
+		else:
+			sorted_data = get_systems_statuses(self, systems, from_cache=False)
+			for data in sorted_data:
+				createStorageChooser_inner(url, pagetype, stoname, data, syslist)
+	sdata['children'] = syslist
+
+	mylist = list()
+	mylist.append(sdata)
+	#mylist.append(sadd)
+	#mylist.append(scfg)
+	dummynode['children'] = mylist
+
+	return dummynode
+
+def createStorageChooser_inner(url, pagetype, stoname, system_data, syslist):
+	ssys = {}
+	if 'nodes' in system_data:
+		title = system_data['name']
+		if system_data['alias'] != '':
+			title = '%s (%s)' % (system_data['alias'], title)
+		ssys['Title'] = 'Cluster %s' % title
+		ssys['cfg_type'] = 'storage'
+		ssys['absolute_url'] = '%s?%s=%s&%s=%s' \
+			% (url, PAGETYPE, CLUSTER_STORAGE, CLUNAME, system_data['name'])
+		ssys['Description'] = 'Configure shared storage of cluster %s' % title
+		ssys['currentItem'] = False
+		ssys['show_children'] = True
+		kids = []
+		for node in system_data['nodes']:
+			createStorageChooser_inner(url, pagetype, stoname, node, kids)
+		ssys['children'] = kids
+	else:
+		if system_data['authed'] is False:
+			return
+		ssys['Title'] = system_data['hostname']
+		ssys['cfg_type'] = 'storage'
+		ssys['absolute_url'] = '%s?%s=%s&%s=%s' \
+			% (url, PAGETYPE, STORAGE, STONAME, system_data['hostname'])
+		ssys['Description'] = 'Configure storage on %s' % system_data['hostname']
+
+		if pagetype == STORAGE:
+			if stoname == system_data['hostname']:
+				ssys['currentItem'] = True
+			else:
+				ssys['currentItem'] = False
+		else:
+			ssys['currentItem'] = False
+	syslist.append(ssys)
+	return
 
 def create_mapper_subitem(storage_report, request, mapper_list, mapper_templ_list):
+	pagetype_req = request.get(PAGETYPE) or '0'
+	mapper_type_req = request.get(PT_MAPPER_TYPE) or ''
+	mapper_id_req = request.get(PT_MAPPER_ID) or ''
+	path_req = request.get(PT_PATH) or ''
+	url = request.get('URL') or '.'
+	hostname = request.get(STONAME) or ''
+
+	mapper_type = None
+	if len(mapper_list) != 0:
+		mapper_type = mapper_list[0].getAttribute('mapper_type')
+	if len(mapper_templ_list) != 0:
+		mapper_type = mapper_templ_list[0].getAttribute('mapper_type')
+	if mapper_type is None:
+		return None
+
+	buff, dummy1, dummy2 = get_pretty_mapper_info(mapper_type)
+	pretty_names = '%ss' % buff
+	pretty_names_desc = 'Manage %ss' % buff
+	pretty_name_desc = 'Manage %s' % buff
+	pretty_new_name = 'New %s' % buff
+	pretty_new_name_desc = 'Create New %s' % buff
+
+	srs_p = {}
+	srs_p['Title'] = pretty_names
+	srs_p['cfg_type'] = 'nodes'
+	srs_p['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s' \
+		% (url, PAGETYPE, VIEW_MAPPERS, STONAME, hostname, PT_MAPPER_TYPE, mapper_type)
+	srs_p['Description'] = pretty_names_desc
+	if pagetype_req in [ VIEW_MAPPERS, VIEW_MAPPER, ADD_SOURCES, CREATE_MAPPER, VIEW_BD ] and mapper_type_req == mapper_type:
+		srs_p['show_children'] = True
+	else:
+		srs_p['show_children'] = False
+
+	if pagetype_req == VIEW_MAPPERS and mapper_type_req == mapper_type:
+		srs_p['currentItem'] = True
+	else:
+		srs_p['currentItem'] = False
+
+	srs_list = []
+
+	# new mapper
+	if len(mapper_templ_list) != 0:
+		sr = {}
+		sr['Title'] = pretty_new_name
+		sr['cfg_type'] = 'nodes'
+		sr['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s' \
+			% (url, PAGETYPE, CREATE_MAPPER, STONAME, hostname, PT_MAPPER_TYPE, mapper_type)
+		sr['Description'] = pretty_new_name_desc
+		sr['show_children'] = False
+
+		if pagetype_req == CREATE_MAPPER and mapper_type_req == mapper_type:
+			sr['currentItem'] = True
+		else:
+			sr['currentItem'] = False
+
+		srs_list.append(sr)
+
+	# existing mappers
+	for sr_xml in mapper_list:
+		sr_id = sr_xml.getAttribute('mapper_id')
+		srname = sr_id.replace('%s:' % mapper_type, '').replace('/dev/', '')
+
+		if srname == '' and mapper_type == MAPPER_VG_TYPE and sr_id == VG_PREFIX:
+			#srname = 'Uninitialized PVs'
+			continue
+
+		sr = {}
+		sr['Title'] = srname
+		sr['cfg_type'] = 'nodes'
+		sr['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s&%s=%s' \
+			% (url, PAGETYPE, VIEW_MAPPER, STONAME, hostname, PT_MAPPER_TYPE, mapper_type, PT_MAPPER_ID, sr_id)
+		sr['Description'] = pretty_name_desc
+
+		if pagetype_req in [ VIEW_MAPPER, ADD_SOURCES, VIEW_BD ] and mapper_id_req == sr_id:
+			sr['currentItem'] = True
+		else:
+			sr['currentItem'] = False
+		sr['show_children'] = False
+
+		# targets
+		tgts_list = []
+		for tgt_xml in storage_report.get_targets(sr_xml):
+			tg_path = tgt_xml.getAttribute('path')
+			tgname = tg_path
+			#if tg_path != path_req:
+			#	continue
+			tg = {}
+			tg['Title'] = tgname
+			tg['cfg_type'] = 'nodes'
+			tg['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s' \
+				% (url, PAGETYPE, VIEW_BD, STONAME, hostname, PT_MAPPER_TYPE, mapper_type, PT_MAPPER_ID, sr_id, PT_PATH, tg_path)
+			tg['Description'] = tgname
+			tg['show_children'] = False
+
+			if pagetype_req == VIEW_BD and path_req == tg_path:
+				tg['currentItem'] = True
+			else:
+				tg['currentItem'] = False
+			tgts_list.append(tg)
+
+		sr['children'] = tgts_list
+		srs_list.append(sr)
+
+	if len(srs_list) != 0:
+		srs_p['children'] = srs_list
+		return srs_p
 
-  try:
-    pagetype_req = request[PAGETYPE]
-  except KeyError, e:
-    pagetype_req = '0'
-  try:
-    mapper_type_req = request[PT_MAPPER_TYPE]
-  except KeyError, e:
-    mapper_type_req = ''
-  try:
-    mapper_id_req = request[PT_MAPPER_ID]
-  except KeyError, e:
-    mapper_id_req = ''
-  try:
-    path_req = request[PT_PATH]
-  except KeyError, e:
-    path_req = ''
-  try:
-    url = request['URL']
-  except KeyError, e:
-    url = "."
-  hostname = request[STONAME]
-
-
-  mapper_type = None
-  if len(mapper_list) != 0:
-    mapper_type = mapper_list[0].getAttribute('mapper_type')
-  if len(mapper_templ_list) != 0:
-    mapper_type = mapper_templ_list[0].getAttribute('mapper_type')
-  if mapper_type is None:
-    return None
-
-
-  buff, dummy1, dummy2 = get_pretty_mapper_info(mapper_type)
-  pretty_names = '%ss' % buff
-  pretty_names_desc = 'Manage %ss' % buff
-  pretty_name_desc = 'Manage %s' % buff
-  pretty_new_name = 'New %s' % buff
-  pretty_new_name_desc = 'Create New %s' % buff
-
-
-  srs_p = {}
-  srs_p['Title'] = pretty_names
-  srs_p['cfg_type'] = "nodes"
-  srs_p['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s' \
-    % (url, PAGETYPE, VIEW_MAPPERS, STONAME, hostname, PT_MAPPER_TYPE, mapper_type)
-  srs_p['Description'] = pretty_names_desc
-  if (pagetype_req == VIEW_MAPPERS or pagetype_req == VIEW_MAPPER or pagetype_req == ADD_SOURCES or pagetype_req == CREATE_MAPPER or pagetype_req == VIEW_BD) and mapper_type_req == mapper_type:
-    srs_p['show_children'] = True
-  else:
-    srs_p['show_children'] = False
-  if pagetype_req == VIEW_MAPPERS and mapper_type_req == mapper_type:
-    srs_p['currentItem'] = True
-  else:
-    srs_p['currentItem'] = False
-
-  srs_list = []
-
-  # new mapper
-  if len(mapper_templ_list) != 0:
-    sr = {}
-    sr['Title'] = pretty_new_name
-    sr['cfg_type'] = "nodes"
-    sr['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s' \
-      % (url, PAGETYPE, CREATE_MAPPER, STONAME, hostname, PT_MAPPER_TYPE, mapper_type)
-    sr['Description'] = pretty_new_name_desc
-    sr['show_children'] = False
-
-    if pagetype_req == CREATE_MAPPER and mapper_type_req == mapper_type:
-      sr['currentItem'] = True
-    else:
-      sr['currentItem'] = False
-
-    srs_list.append(sr)
-
-  # existing mappers
-  for sr_xml in mapper_list:
-    sr_id = sr_xml.getAttribute('mapper_id')
-    srname = sr_id.replace('%s:' % mapper_type, '').replace('/dev/', '')
-
-    if srname == '' and mapper_type == MAPPER_VG_TYPE and sr_id == VG_PREFIX:
-      #srname = 'Uninitialized PVs'
-      continue
-
-    sr = {}
-    sr['Title'] = srname
-    sr['cfg_type'] = "nodes"
-    sr['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s&%s=%s' \
-      % (url, PAGETYPE, VIEW_MAPPER, STONAME, hostname, PT_MAPPER_TYPE, mapper_type, PT_MAPPER_ID, sr_id)
-    sr['Description'] = pretty_name_desc
-
-    if (pagetype_req == VIEW_MAPPER or pagetype_req == ADD_SOURCES or pagetype_req == VIEW_BD) and mapper_id_req == sr_id:
-      sr['currentItem'] = True
-    else:
-      sr['currentItem'] = False
-    sr['show_children'] = False
-
-    # targets
-    tgts_list = []
-    for tgt_xml in storage_report.get_targets(sr_xml):
-      tg_path = tgt_xml.getAttribute('path')
-      tgname = tg_path
-      #if tg_path != path_req:
-      #  continue
-      tg = {}
-      tg['Title'] = tgname
-      tg['cfg_type'] = "nodes"
-      tg['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s' \
-        % (url, PAGETYPE, VIEW_BD, STONAME, hostname, PT_MAPPER_TYPE, mapper_type, PT_MAPPER_ID, sr_id, PT_PATH, tg_path)
-      tg['Description'] = tgname
-      tg['show_children'] = False
-
-      if pagetype_req == VIEW_BD and path_req == tg_path:
-        tg['currentItem'] = True
-      else:
-        tg['currentItem'] = False
-      tgts_list.append(tg)
-
-    sr['children'] = tgts_list
-    srs_list.append(sr)
-
-  if len(srs_list) != 0:
-    srs_p['children'] = srs_list
-    return srs_p
-  return None
-
-
-
+	return None
 
 def createStorageConfigTree(self, request, storage_report):
-  dummynode = {}
-  if storage_report is None:
-    return dummynode
-
-  try:
-    pagetype = request[PAGETYPE]
-  except KeyError, e:
-    pagetype = '0'
-  try:
-    mapper_type = request[PT_MAPPER_TYPE]
-  except KeyError, e:
-    mapper_type = ''
-  try:
-    mapper_id = request[PT_MAPPER_ID]
-  except KeyError, e:
-    mapper_id = ''
-  try:
-    path = request[PT_PATH]
-  except KeyError, e:
-    path = ''
-  try:
-    url = request['URL']
-  except KeyError, e:
-    url = "."
-  hostname = request[STONAME]
-
-
-  ### Hard Drives ###
-
-  hds_pretty_name, hd_pretty_name, dummy = get_pretty_mapper_info(MAPPER_SYS_TYPE)
-
-  hds_p = {}
-  hds_p['Title'] = hds_pretty_name
-  hds_p['cfg_type'] = "nodes"
-  hds_p['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s&%s=%s' \
-    % (url, PAGETYPE, VIEW_BDS, STONAME, hostname, PT_MAPPER_TYPE, MAPPER_SYS_TYPE, PT_MAPPER_ID, SYSTEM_PREFIX)
-  hds_p['Description'] = "Manage %s" % hds_pretty_name
-  if (pagetype == VIEW_BDS or pagetype == VIEW_BD) and mapper_type == MAPPER_SYS_TYPE:
-    hds_p['show_children'] = True
-  else:
-    hds_p['show_children'] = False
-  if pagetype == VIEW_BDS and mapper_type == MAPPER_SYS_TYPE:
-    hds_p['currentItem'] = True
-  else:
-    hds_p['currentItem'] = False
-
-  targets_list = storage_report.get_targets(storage_report.get_mapper(SYSTEM_PREFIX))
-
-  hds_list = []
-  for target in targets_list:
-    sys_id = target.getAttribute('mapper_id')
-    hd_path = target.getAttribute('path')
-
-    hd = {}
-    hd['Title'] = hd_path.replace('/dev/', '')
-    hd['cfg_type'] = "nodes"
-    hd['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s' \
-      % (url, PAGETYPE, VIEW_BD, STONAME, hostname, PT_MAPPER_TYPE, MAPPER_SYS_TYPE, PT_MAPPER_ID, sys_id, PT_PATH, hd_path)
-    hd['Description'] = 'Manage %s' % hd_pretty_name
-    hd['show_children'] = False
-
-    if pagetype == VIEW_BD and mapper_id == sys_id and path == hd_path:
-      hd['currentItem'] = True
-    else:
-      hd['currentItem'] = False
-
-    hds_list.append(hd)
-
-  hds_p['children'] = hds_list
-
-
-
-  ## mappers ##
-
-  main_kids = [hds_p]
-
-  mappers_dir = storage_report.get_mappers_dir()
-  mapper_templs_dir = storage_report.get_mapper_temps_dir()
-  glo_dir = {}
-  for cur_type in mappers_dir:
-    glo_dir[cur_type] = [mappers_dir[cur_type], []]
-  for cur_type in mapper_templs_dir:
-    if cur_type not in glo_dir:
-      glo_dir[cur_type] = [[], mapper_templs_dir[cur_type]]
-    else:
-      glo_dir[cur_type][1] = mapper_templs_dir[cur_type]
-
-  for cur_type in glo_dir:
-    if cur_type == MAPPER_SYS_TYPE:
-      continue
-    item = create_mapper_subitem(storage_report, request, glo_dir[cur_type][0], glo_dir[cur_type][1])
-    if item is None:
-      continue
-    else:
-      main_kids.append(item)
-  dummynode['children'] = main_kids
-  return dummynode
+	dummynode = {}
+	if storage_report is None:
+		return dummynode
+
+	pagetype = request.get(PAGETYPE) or '0'
+	mapper_type = request.get(PT_MAPPER_TYPE) or ''
+	mapper_id = request.get(PT_MAPPER_ID) or ''
+	path = request.get(PT_PATH) or ''
+	url = request.get('URL') or '.'
+	hostname = request.get(STONAME) or ''
+
+	### Hard Drives ###
+
+	hds_pretty_name, hd_pretty_name, dummy = get_pretty_mapper_info(MAPPER_SYS_TYPE)
+
+	hds_p = {}
+	hds_p['Title'] = hds_pretty_name
+	hds_p['cfg_type'] = 'nodes'
+	hds_p['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s&%s=%s' \
+		% (url, PAGETYPE, VIEW_BDS, STONAME, hostname, PT_MAPPER_TYPE, MAPPER_SYS_TYPE, PT_MAPPER_ID, SYSTEM_PREFIX)
+	hds_p['Description'] = 'Manage %s' % hds_pretty_name
+
+	if (pagetype == VIEW_BDS or pagetype == VIEW_BD) and mapper_type == MAPPER_SYS_TYPE:
+		hds_p['show_children'] = True
+		if pagetype == VIEW_BDS:
+			hds_p['currentItem'] = True
+		else:
+			hds_p['currentItem'] = False
+	else:
+		hds_p['show_children'] = False
+
+	targets_list = storage_report.get_targets(storage_report.get_mapper(SYSTEM_PREFIX))
+
+	hds_list = []
+	for target in targets_list:
+		sys_id = target.getAttribute('mapper_id')
+		hd_path = target.getAttribute('path')
+
+		hd = {}
+		hd['Title'] = hd_path.replace('/dev/', '')
+		hd['cfg_type'] = 'nodes'
+		hd['absolute_url'] = '%s?%s=%s&%s=%s&%s=%s&%s=%s&%s=%s' \
+			% (url, PAGETYPE, VIEW_BD, STONAME, hostname, PT_MAPPER_TYPE, MAPPER_SYS_TYPE, PT_MAPPER_ID, sys_id, PT_PATH, hd_path)
+		hd['Description'] = 'Manage %s' % hd_pretty_name
+		hd['show_children'] = False
+
+		if pagetype == VIEW_BD and mapper_id == sys_id and path == hd_path:
+			hd['currentItem'] = True
+		else:
+			hd['currentItem'] = False
+
+		hds_list.append(hd)
+
+	hds_p['children'] = hds_list
+
+	## mappers ##
+
+	main_kids = [ hds_p ]
+
+	mappers_dir = storage_report.get_mappers_dir()
+	mapper_templs_dir = storage_report.get_mapper_temps_dir()
+
+	glo_dir = {}
+	for cur_type in mappers_dir:
+		glo_dir[cur_type] = [ mappers_dir[cur_type], [] ]
+
+	for cur_type in mapper_templs_dir:
+		if cur_type not in glo_dir:
+			glo_dir[cur_type] = [ [], mapper_templs_dir[cur_type] ]
+		else:
+			glo_dir[cur_type][1] = mapper_templs_dir[cur_type]
+
+	for cur_type in glo_dir:
+		if cur_type == MAPPER_SYS_TYPE:
+			continue
+		item = create_mapper_subitem(storage_report, request, glo_dir[cur_type][0], glo_dir[cur_type][1])
+		if item is None:
+			continue
+		else:
+			main_kids.append(item)
 
+	dummynode['children'] = main_kids
+	return dummynode
 
 def getStorageURL(self, request, hostname):
-  # return URL to manage this storage system
-  try:
-    baseurl = request['URL']
-  except KeyError, e:
-    baseurl = "."
-  return '%s?%s=%s&%s=%s' % (baseurl, PAGETYPE, str(STORAGE), STONAME, hostname)
+	# return URL to manage this storage system
+	baseurl = request.get('URL') or '.'
+	return '%s?%s=%s&%s=%s' % (baseurl, PAGETYPE, str(STORAGE), STONAME, hostname)




More information about the Cluster-devel mailing list