[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

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



CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe sourceware org	2007-01-18 02:48:37

Modified files:
	luci/site/luci/Extensions: cluster_adapters.py 

Log message:
	add support for the new resource agents

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.204&r2=1.205

--- conga/luci/site/luci/Extensions/cluster_adapters.py	2007/01/17 22:14:02	1.204
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2007/01/18 02:48:37	1.205
@@ -17,6 +17,11 @@
 from NFSExport import NFSExport
 from Service import Service
 from Netfs import Netfs
+from Apache import Apache
+from MySQL import MySQL
+from Postgres8 import Postgres8
+from Tomcat5 import Tomcat5
+from OpenLDAP import OpenLDAP
 from Vm import Vm
 from Script import Script
 from Samba import Samba
@@ -119,7 +124,7 @@
 
 	system_list, incomplete, errors, messages = parseHostForm(request, check_certs)
 	add_cluster['nodes'] = system_list
-	
+
 	for i in system_list:
 		cur_system = system_list[i]
 
@@ -150,7 +155,7 @@
 			try:
 				if prev_auth:
 					messages.append('Host %s is already authenticated.' \
-						% cur_host) 
+						% cur_host)
 				else:
 					rc.auth(cur_passwd)
 
@@ -258,7 +263,7 @@
 		try:
 			rc = RicciCommunicator(i)
 			if not rc:
-				raise 'rc is None'
+				raise Exception, 'rc is None'
 		except Exception, e:
 			msg = 'Unable to connect to the ricci agent on %s: %s' % (i, str(e))
 			errors.append(msg)
@@ -327,7 +332,7 @@
 		except Exception, e:
 			luci_log.debug_verbose('VACN1: %s: %s' % (clusterName, str(e)))
 			return (False, { 'errors': [ 'The database object for %s is missing.' % clusterName ] })
-		
+
 		try:
 			cluster_os = cluster_folder.manage_getProperty('cluster_os')
 			if not cluster_os:
@@ -369,7 +374,7 @@
 
 	system_list, incomplete, errors, messages = parseHostForm(request, check_certs)
 	add_cluster['nodes'] = system_list
-	
+
 	for i in system_list:
 		cur_system = system_list[i]
 
@@ -399,7 +404,7 @@
 			try:
 				if prev_auth:
 					messages.append('Host %s is already authenticated.' \
-						% cur_host) 
+						% cur_host)
 				else:
 					rc.auth(cur_passwd)
 
@@ -855,7 +860,7 @@
 		return (False, {'errors': errors})
 
 	return (True, {'messages': ['Resource added successfully']})
-	
+
 ## Cluster properties form validation routines
 
 # rhel5 cluster version
@@ -1215,7 +1220,7 @@
       raise Exception, 'cluster name from model.getClusterName() is blank'
   except Exception, e:
     luci_log.debug_verbose('VCC5: error: getClusterName: %s' % str(e))
-    errors.append('Unable to determine cluster name from model') 
+    errors.append('Unable to determine cluster name from model')
 
   if len(errors) > 0:
     return (retcode, {'errors': errors, 'messages': messages})
@@ -1251,7 +1256,7 @@
   errors = list()
   messages = list()
   rc = None
-                                                                                
+
   try:
     model = request.SESSION.get('model')
     if not model:
@@ -1266,12 +1271,12 @@
       except:
         luci_log.debug_verbose('VFE: no model, no cluster name')
         return (False, {'errors': ['No cluster model was found.']})
-                                                                                
+
     try:
       model = getModelForCluster(self, cluname)
     except:
       model = None
-                                                                                
+
     if model is None:
       luci_log.debug_verbose('VFE: unable to get model from session')
       return (False, {'errors': ['No cluster model was found.']})
@@ -1312,7 +1317,7 @@
         raise Exception, 'cluster name from model.getClusterName() is blank'
     except Exception, e:
       luci_log.debug_verbose('VFA: error: getClusterName: %s' % str(e))
-      errors.append('Unable to determine cluster name from model') 
+      errors.append('Unable to determine cluster name from model')
 
     if not rc:
       rc = getRicciAgent(self, clustername)
@@ -1345,7 +1350,7 @@
   errors = list()
   messages = list()
   rc = None
-                                                                                
+
   try:
     model = request.SESSION.get('model')
     if not model:
@@ -1360,12 +1365,12 @@
       except:
         luci_log.debug_verbose('VFE: no model, no cluster name')
         return (False, {'errors': ['No cluster model was found.']})
-                                                                                
+
     try:
       model = getModelForCluster(self, cluname)
     except:
       model = None
-                                                                                
+
     if model is None:
       luci_log.debug_verbose('VFE: unable to get model from session')
       return (False, {'errors': ['No cluster model was found.']})
@@ -1409,7 +1414,7 @@
         raise Exception, 'cluster name from model.getClusterName() is blank'
     except Exception, e:
       luci_log.debug_verbose('VFA: error: getClusterName: %s' % str(e))
-      errors.append('Unable to determine cluster name from model') 
+      errors.append('Unable to determine cluster name from model')
 
     if not rc:
       rc = getRicciAgent(self, clustername)
@@ -1519,10 +1524,10 @@
 				break
 		if delete_target is not None:
 			try:
-				node.getChildren()[0].removeChild(l)
+				node.getChildren()[0].removeChild(delete_target)
 			except Exception, e:
 				luci_log.debug_verbose('vNFC6a: %s: %s' % (method_id, str(e)))
-				return (False, {'errors': ['An error occurred while deleting fence method %s' % method_id ]}) 
+				return (False, {'errors': ['An error occurred while deleting fence method %s' % method_id ]})
 		else:
 			return (True, {'messages': ['No changes were made.'] })
 
@@ -1563,7 +1568,7 @@
 				return (False, {'errors': [ 'Unable to determine what device the current instance uses.' ]})
 
 			try:
-				parent_form = form_hash[parent][1].append(dummy_form)
+				form_hash[parent][1].append(dummy_form)
 				del dummy_form['fence_instance']
 			except Exception, e:
 				luci_log.debug_verbose('vNFC10: no parent for instance')
@@ -1777,7 +1782,7 @@
   errors = list()
   messages = list()
   rc = None
-                                                                                
+
   try:
     model = request.SESSION.get('model')
     if not model:
@@ -1792,12 +1797,12 @@
       except:
         luci_log.debug_verbose('VFE: no model, no cluster name')
         return (False, {'errors': ['No cluster model was found.']})
-                                                                                
+
     try:
       model = getModelForCluster(self, cluname)
     except:
       model = None
-                                                                                
+
     if model is None:
       luci_log.debug_verbose('VFE: unable to get model from session')
       return (False, {'errors': ['No cluster model was found.']})
@@ -1844,12 +1849,12 @@
   except:
     error_code = FD_VAL_FAIL
     error_string = "Fence device %s could not be removed from configuration" % fencedev_name
- 
+
   try:
     model.removeFenceInstancesForFenceDevice(fencedev_name)
   except:
     luci_log.debug_verbose('VFD: Could not remove fence instances for')
-     
+
 
   if error_code == FD_VAL_SUCCESS:
     messages.append(error_string)
@@ -1871,7 +1876,7 @@
         raise Exception, 'cluster name from model.getClusterName() is blank'
     except Exception, e:
       luci_log.debug_verbose('VFA: error: getClusterName: %s' % str(e))
-      errors.append('Unable to determine cluster name from model') 
+      errors.append('Unable to determine cluster name from model')
 
     if not rc:
       rc = getRicciAgent(self, clustername)
@@ -1960,7 +1965,7 @@
 		luci_log.debug_verbose('VDP5: RC %s: %s' % (nodename_resolved, str(e)))
 		errors.append('Unable to connect to the ricci agent on %s to update cluster daemon properties' % nodename_resolved)
 		return (False, {'errors': errors})
-		
+
 	batch_id, result = updateServices(rc, enable_list, disable_list)
 	if batch_id is None or result is None:
 		luci_log.debug_verbose('VDP6: setCluserConf: batchid or result is None')
@@ -2716,7 +2721,7 @@
 		except Exception, e:
 			luci_log.debug_verbose('GRA4b: %s' % str(e))
 			cur_alias = None
-			
+
 		if (cur_name is not None and cluname != cur_name) and (cur_alias is not None and cluname != cur_alias):
 			try:
 				luci_log.debug('GRA5: %s reports it\'s in cluster %s:%s; we expect %s' \
@@ -3176,7 +3181,7 @@
 	if batch_number is None or result is None:
 		luci_log.debug_verbose('serviceRestart2: %s failed' % svcname)
 		return None
-				
+
 	try:
 		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_RESTART, "Restarting service \'%s\'" % svcname)
 	except Exception, e:
@@ -4174,8 +4179,7 @@
         except:
           luci_log.debug_verbose('GNI0: unable to determine cluster name')
           return {}
-      
- 
+
   for item in nodelist:
     map = {}
     name = item['name']
@@ -4285,7 +4289,7 @@
               clustername = model.getClusterName()
               node_hash = {}
               node_hash['nodename'] = node.getName().strip()
-              node_hash['nodeurl'] = baseurl + "?clustername=" + clustername + "&nodename=" + node.getName() + "&pagetype=" + NODE 
+              node_hash['nodeurl'] = baseurl + "?clustername=" + clustername + "&nodename=" + node.getName() + "&pagetype=" + NODE
               nodes_used.append(node_hash)
 
       map['nodesused'] = nodes_used
@@ -4299,7 +4303,7 @@
       return fd
 
   raise
-  
+
 def getFenceInfo(self, model, request):
   if not model:
     luci_log.debug_verbose('getFenceInfo00: model is None')
@@ -4342,12 +4346,12 @@
       luci_log.debug_verbose('getFenceInfo2: unable to extract nodename: %s' \
           % str(e))
       return {}
-    
+
   #Here we need to get fences for a node - just the first two levels
   #Each level has its own list of fence devs used in that level
   #For each fence dev, a list of instance structs is appended
   #In addition, for each level, a list of available but unused fence devs
-  #is returned. 
+  #is returned.
   try:
     node = model.retrieveNodeByName(nodename)
   except GeneralError, e:
@@ -4396,7 +4400,7 @@
             if kee == "name":
               continue #Don't duplicate name attr
             fencedev[kee] = kidattrs[kee]
-          #This fencedev struct is complete, and needs to be placed on the 
+          #This fencedev struct is complete, and needs to be placed on the
           #level1 Q. Because it is non-shared, we should set last_kid_fd
           #to none.
           last_kid_fd = None
@@ -4425,7 +4429,7 @@
               fencedev['unknown'] = True
               fencedev['prettyname'] = fd.getAgentType()
             fencedev['isShared'] = True
-            fencedev['cfgurl'] = baseurl + "?clustername=" + clustername + "&fencename=" + fd.getName().strip() + "&pagetype=" + FENCEDEV 
+            fencedev['cfgurl'] = baseurl + "?clustername=" + clustername + "&fencename=" + fd.getName().strip() + "&pagetype=" + FENCEDEV
             fencedev['id'] = str(major_num)
             major_num = major_num + 1
             inlist = list()
@@ -4441,7 +4445,7 @@
               if kee == "name":
                 continue
               instance_struct[kee] = kidattrs[kee]
-            inlist.append(instance_struct) 
+            inlist.append(instance_struct)
             level1.append(fencedev)
             last_kid_fd = fencedev
             continue
@@ -4503,7 +4507,7 @@
             if kee == "name":
               continue #Don't duplicate name attr
             fencedev[kee] = kidattrs[kee]
-          #This fencedev struct is complete, and needs to be placed on the 
+          #This fencedev struct is complete, and needs to be placed on the
           #level2 Q. Because it is non-shared, we should set last_kid_fd
           #to none.
           last_kid_fd = None
@@ -4532,7 +4536,7 @@
               fencedev['unknown'] = True
               fencedev['prettyname'] = fd.getAgentType()
             fencedev['isShared'] = True
-            fencedev['cfgurl'] = baseurl + "?clustername=" + clustername + "&fencename=" + fd.getName().strip() + "&pagetype=" + FENCEDEV 
+            fencedev['cfgurl'] = baseurl + "?clustername=" + clustername + "&fencename=" + fd.getName().strip() + "&pagetype=" + FENCEDEV
             fencedev['id'] = str(major_num)
             major_num = major_num + 1
             inlist = list()
@@ -4548,7 +4552,7 @@
               if kee == "name":
                 continue
               instance_struct[kee] = kidattrs[kee]
-            inlist.append(instance_struct) 
+            inlist.append(instance_struct)
             level2.append(fencedev)
             last_kid_fd = fencedev
             continue
@@ -4576,8 +4580,8 @@
         shared2.append(shared_struct)
     map['shared2'] = shared2
 
-  return map    
-      
+  return map
+
 def getFencesInfo(self, model, request):
   map = {}
   if not model:
@@ -4625,7 +4629,7 @@
                 continue
               node_hash = {}
               node_hash['nodename'] = node.getName().strip()
-              node_hash['nodeurl'] = baseurl + "?clustername=" + clustername + "&nodename=" + node.getName() + "&pagetype=" + NODE 
+              node_hash['nodeurl'] = baseurl + "?clustername=" + clustername + "&nodename=" + node.getName() + "&pagetype=" + NODE
               nodes_used.append(node_hash)
 
       fencedev['nodesused'] = nodes_used
@@ -4634,7 +4638,6 @@
   map['fencedevs'] = fencedevs
   return map
 
-    
 def getLogsForNode(self, request):
 	try:
 		nodename = request['nodename']
@@ -4700,7 +4703,7 @@
     xenvmname = req['servicename']
   except KeyError, e:
     isNew = True
-  
+
   if isNew == True:
     xvm = Vm()
     xvm.addAttribute("name", req.form['xenvmname'])
@@ -4829,7 +4832,7 @@
       node_report = {}
       node_report['isnodecreation'] = True
       node_report['iserror'] = False  #Default value
-      node_report['desc'] = item[1].getProperty(FLAG_DESC) 
+      node_report['desc'] = item[1].getProperty(FLAG_DESC)
       batch_xml = None
       ricci = item[0].split("____") #This removes the 'flag' suffix
 
@@ -4885,7 +4888,7 @@
       if batch_xml is None:  #The job is done and gone from queue
         if redirect_message == False: #We have not displayed this message yet
           node_report['desc'] = REDIRECT_MSG
-          node_report['iserror'] = True 
+          node_report['iserror'] = True
           node_report['errormessage'] = ""
           nodereports.append(node_report)
           redirect_message = True
@@ -4984,7 +4987,7 @@
             luci_log.debug_verbose('ICB16: last_status err: %s %d: %s' \
               % (item[0], creation_status, str(e)))
           continue
-          
+
     else:
       node_report = {}
       node_report['isnodecreation'] = False
@@ -5306,696 +5309,1464 @@
 	response.redirect(request['URL'] + "?pagetype=" + RESOURCES + "&clustername=" + clustername + '&busyfirst=true')
 
 def addIp(request, form=None):
+	errors = list()
+
 	if form is None:
 		form = request.form
 
 	if not form:
-		luci_log.debug_verbose('addIp error: form is missing')
+		luci_log.debug_verbose('addIp0: form is missing')
 		return None
 
 	model = request.SESSION.get('model')
 	if not model:
-		luci_log.debug_verbose('addIp error: model is missing')
+		luci_log.debug_verbose('addIp1: model is missing')
 		return None
 
+	res = None
 	if form.has_key('edit'):
 		try:
 			oldname = form['oldname'].strip()
 			if not oldname:
-				raise KeyError, 'oldname is blank.'
-			res = getResourceForEdit(model, oldname)
+				raise Exception, 'oldname is blank.'
+
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e1:
+				errors.append('No IP resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug_verbose('addIp error: %s' % str(e))
-			return None
+			errors.append('No original name was found for this IP resource.')
 	else:
 		try:
 			res = Ip()
 			if not res:
-				raise Exception, 'apply(Ip) is None'
+				raise Exception, 'res is None'
 		except Exception, e:
-			luci_log.debug_verbose('addIp error: %s' % str(e))
-			return None
+			errors.append('An error occurred while creating an IP resource.')
+			luci_log.debug_verbose('addIp3: %s' % str(e))
 
 	if not res:
-		luci_log.debug_verbose('addIp error: res is none')
-		return None
+		return [None, None, errors]
 
-	errors = list()
 	try:
 		addr = form['ip_address'].strip()
 		if not addr:
 			raise KeyError, 'ip_address is blank'
 		# XXX: validate IP addr
-		res.attr_hash['address'] = addr
+		res.addAttribute('address', addr)
 	except KeyError, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addIp error: %s' % err)
+		luci_log.debug_verbose('addIp4: %s' % err)
 
 	if 'monitorLink' in form:
-		res.attr_hash['monitor_link'] = '1'
+		res.addAttribute('monitor_link', '1')
 	else:
-		res.attr_hash['monitor_link'] = '0'
+		res.addAttribute('monitor_link', '0')
 
 	if len(errors) > 1:
 		return [None, None, errors]
 	return [res, model, None]
 
 def addFs(request, form=None):
+	errors = list()
+
 	if form is None:
 		form = request.form
 
 	if not form:
-		luci_log.debug_verbose('addFs error: form is missing')
+		luci_log.debug_verbose('addFs0: form is missing')
 		return None
 
 	model = request.SESSION.get('model')
 	if not model:
-		luci_log.debug_verbose('addFs error: model is missing')
+		luci_log.debug_verbose('addFs1: model is missing')
 		return None
 
+	res = None
 	if form.has_key('edit'):
 		try:
 			oldname = form['oldname'].strip()
 			if not oldname:
-				raise KeyError, 'oldname is blank.'
-			res = getResourceForEdit(model, oldname)
+				raise Exception, 'oldname is blank.'
+
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e1:
+				errors.append('No filesystem resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug_verbose('addFs error: %s' % str(e))
-			return None
+			errors.append('No original name was found for this filesystem resource.')
+			luci_log.debug_verbose('addFs3: %s' % str(e))
 	else:
 		try:
 			res = Fs()
 			if not res:
-				raise Exception, 'apply(Fs) is None'
+				raise Exception, 'res is None'
 		except Exception, e:
-			luci_log.debug_verbose('addFs error: %s' % str(e))
-			return None
+			errors.append('An error occurred while creating a filesystem resource.')
+			luci_log.debug_verbose('addFs4: %s' % str(e))
 
 	if not res:
-		luci_log.debug_verbose('addFs error: fs obj was not created')
-		return None
+		return [None, None, errors]
 
 	# XXX: sanity check these fields
-	errors = list()
 	try:
 		name = form['resourceName'].strip()
-		res.attr_hash['name'] = name
+		if not name:
+			raise Exception, 'No name was given for this filesystem resource.'
+		res.addAttribute('name', name)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addFs error: %s' % err)
+		luci_log.debug_verbose('addFs5: %s' % err)
 
 	try:
 		mountpoint = form['mountpoint'].strip()
-		res.attr_hash['mountpoint'] = mountpoint
+		if not mountpoint:
+			raise Exception, 'No mount point was given for this filesystem resource.'
+		res.addAttribute('mountpoint', mountpoint)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addFs error: %s' % err)
+		luci_log.debug_verbose('addFs6: %s' % err)
 
 	try:
 		device = form['device'].strip()
-		res.attr_hash['device'] = device
+		if not device:
+			raise Exception, 'No device was given for this filesystem resource.'
+		res.addAttribute('device', device)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addFs error: %s' % err)
+		luci_log.debug_verbose('addFs7: %s' % err)
 
 	try:
 		options = form['options'].strip()
-		res.attr_hash['options'] = options
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('options')
+		except:
+			pass
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addFs error: %s' % err)
+		luci_log.debug_verbose('addFs8: %s' % err)
 
 	try:
 		fstype = form['fstype'].strip()
-		res.attr_hash['fstype'] = fstype
+		if not fstype:
+			raise Exception, 'No filesystem type was given for this filesystem resource.'
+		res.addAttribute('fstype', fstype)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addFs error: %s' % err)
+		luci_log.debug_verbose('addFs9: %s' % err)
 
 	try:
 		fsid = form['fsid'].strip()
-		res.attr_hash['fsid'] = fsid
+		if not fsid:
+			raise Exception, 'No filesystem ID was given for this filesystem resource.'
+		res.addAttribute('fsid', fsid)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addFs error: %s' % err)
+		luci_log.debug_verbose('addFs10: %s' % err)
 
 	if form.has_key('forceunmount'):
-		res.attr_hash['force_unmount'] = '1'
+		res.addAttribute('force_unmount', '1')
 	else:
-		res.attr_hash['force_unmount'] = '0'
+		res.addAttribute('force_unmount', '0')
 
 	if form.has_key('selffence'):
-		res.attr_hash['self_fence'] = '1'
+		res.addAttribute('self_fence', '1')
 	else:
-		res.attr_hash['self_fence'] = '0'
+		res.addAttribute('self_fence', '0')
 
 	if form.has_key('checkfs'):
-		res.attr_hash['force_fsck'] = '1'
+		res.addAttribute('force_fsck', '1')
 	else:
-		res.attr_hash['force_fsck'] = '0'
+		res.addAttribute('force_fsck', '0')
 
 	if len(errors) > 1:
 		return [None, None, errors]
 	return [res, model, None]
 
 def addGfs(request, form=None):
+	errors = list()
+
 	if form is None:
 		form = request.form
 
 	if not form:
-		luci_log.debug_verbose('addGfs error: form is missing')
+		luci_log.debug_verbose('addGfs0: form is missing')
 		return None
 
 	model = request.SESSION.get('model')
 	if not model:
-		luci_log.debug_verbose('addGfs error: model is missing')
+		luci_log.debug_verbose('addGfs1: model is missing')
 		return None
 
+	res = None
 	if form.has_key('edit'):
 		try:
 			oldname = form['oldname'].strip()
 			if not oldname:
-				raise KeyError, 'oldname is blank.'
-			res = getResourceForEdit(model, oldname)
-			if not res:
-				luci_log.debug('resource %s was not found for editing' % oldname)
-				return None
+				raise Exception, 'oldname is blank'
+
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e1:
+				errors.append('No filesystem resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug('resource %s was not found for editing: %s' \
-				% (oldname, str(e)))
-			return None
+			errors.append('No original name was found for this cluster filesystem resource.')
+			luci_log.debug_verbose('addGfs2: %s' % str(e))
 	else:
 		try:
 			res = Clusterfs()
 			if not res:
-				raise Exception, 'apply(Clusterfs) is None'
+				raise Exception, 'res is None'
 		except Exception, e:
-			luci_log.debug('addGfs error: %s' % str(e))
-			return None
-		except:
-			luci_log.debug('addGfs error')
-			return None
+			errors.append('An error occurred while creating a cluster filesystem resource.')
+			luci_log.debug('addGfs3: %s' % str(e))
+
+	if not res:
+		return [None, None, errors]
 
 	# XXX: sanity check these fields
-	errors = list()
 	try:
 		name = form['resourceName'].strip()
 		if not name:
-			raise KeyError, 'resourceName is blank'
-		res.attr_hash['name'] = name
+			raise Exception, 'No name was given for this cluster filesystem resource.'
+		res.addAttribute('name', name)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addGfs error: %s' % err)
+		luci_log.debug_verbose('addGfs4: %s' % err)
 
 	try:
 		mountpoint = form['mountpoint'].strip()
-		res.attr_hash['mountpoint'] = mountpoint
+		if not mountpoint:
+			raise Exception, 'No mount point was given for this cluster filesystem resource.'
+		res.addAttribute('mountpoint', mountpoint)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addGfs error: %s' % err)
+		luci_log.debug_verbose('addGfs5: %s' % err)
 
 	try:
 		device = form['device'].strip()
-		res.attr_hash['device'] = device
+		if not device:
+			raise Exception, 'No device was given for this cluster filesystem resource.'
+		res.addAttribute('device', device)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addGfs error: %s' % err)
+		luci_log.debug_verbose('addGfs6: %s' % err)
 
 	try:
 		options = form['options'].strip()
-		res.attr_hash['options'] = options
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('options')
+		except:
+			pass
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addGfs error: %s' % err)
+		luci_log.debug_verbose('addGfs7: %s' % err)
 
 	try:
 		fsid = form['fsid'].strip()
-		res.attr_hash['fsid'] = fsid
+		if not fsid:
+			raise Exception, 'No filesystem ID was given for this cluster filesystem resource.'
+		res.addAttribute('fsid', fsid)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addGfs error: %s' % err)
+		luci_log.debug_verbose('addGfs8: %s' % err)
 
 	if form.has_key('forceunmount'):
-		res.attr_hash['force_unmount'] = '1'
+		res.addAttribute('force_unmount', '1')
 	else:
-		res.attr_hash['force_unmount'] = '0'
+		res.addAttribute('force_unmount', '0')
 
 	if len(errors) > 1:
 		return [None, None, errors]
+
 	return [res, model, None]
 
 def addNfsm(request, form=None):
+	errors = list()
+
 	if form is None:
 		form = request.form
 
 	if not form:
-		luci_log.debug_verbose('addNfsm error: form is missing')
+		luci_log.debug_verbose('addNfsm0: form is missing')
 		return None
 
 	model = request.SESSION.get('model')
 	if not model:
-		luci_log.debug_verbose('addNfsm error: model is missing')
+		luci_log.debug_verbose('addNfsm1: model is missing')
 		return None
 
+	res = None
 	if form.has_key('edit'):
 		try:
 			oldname = form['oldname'].strip()
 			if not oldname:
-				raise KeyError, 'oldname is blank.'
-			res = getResourceForEdit(model, oldname)
+				raise Exception, 'oldname is blank'
+
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e1:
+				errors.append('No NFS mount resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug_verbose('addNfsm error: %s' % str(e))
-			return None
+			errors.append('No original name was found for this NFS mount resource.')
+			luci_log.debug_verbose('addNfsm2: %s' % str(e))
 	else:
 		try:
 			res = Netfs()
+			if not res:
+				raise Exception, 'res is None'
 		except Exception, e:
-			luci_log.debug_verbose('addNfsm error: %s' % str(e))
-			return None
+			errors.append('An error occurred while creating a NFS mount resource.')
+			luci_log.debug_verbose('addNfsm3: %s' % str(e))
 
 	if not res:
-		return None
+		return [None, None, errors]
 
 	# XXX: sanity check these fields
-	errors = list()
 	try:
 		name = form['resourceName'].strip()
 		if not name:
-			raise KeyError, 'resourceName is blank'
-		res.attr_hash['name'] = name
+			raise Exception, 'No name was given for this NFS mount resource.'
+		res.addAttribute('name', name)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsm error: %s' % err)
+		luci_log.debug_verbose('addNfsm4: %s' % err)
 
 	try:
 		mountpoint = form['mountpoint'].strip()
-		res.attr_hash['mountpoint'] = mountpoint
+		if not mountpoint:
+			raise Exception, 'No mount point was given for NFS mount resource.'
+		res.addAttribute('mountpoint', mountpoint)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsm error: %s' % err)
-		
+		luci_log.debug_verbose('addNfsm5: %s' % err)
+
 	try:
 		host = form['host'].strip()
-		res.attr_hash['host'] = host
+		if not host:
+			raise Exception, 'No host server was given for this NFS mount resource.'
+		res.addAttribute('host', host)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsm error: %s' % err)
+		luci_log.debug_verbose('addNfsm6 error: %s' % err)
 
 	try:
 		options = form['options'].strip()
-		res.attr_hash['options'] = options
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('options')
+		except:
+			pass
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsm error: %s' % err)
+		luci_log.debug_verbose('addNfsm7: %s' % err)
 
 	try:
 		exportpath = form['exportpath'].strip()
-		res.attr_hash['exportpath'] = exportpath 
+		if not exportpath:
+			raise Exception, 'No export path was given for this NFS mount resource.'
+		res.addAttribute('exportpath', exportpath)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsm error: %s' % err)
+		luci_log.debug_verbose('addNfsm8: %s' % err)
 
 	try:
 		nfstype = form['nfstype'].strip().lower()
 		if nfstype != 'nfs' and nfstype != 'nfs4':
-			raise KeyError, 'invalid nfs type: %s' % nfstype
-		res.attr_hash['nfstype'] = nfstype
+			raise Exception, 'An invalid NFS version \"%s\" was given.' % nfstype
+		res.addAttribute('nfstype', nfstype)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsm error: %s' % err)
+		luci_log.debug_verbose('addNfsm9: %s' % err)
 
 	if form.has_key('forceunmount'):
-		res.attr_hash['force_unmount'] = '1'
+		res.addAttribute('force_unmount', '1')
 	else:
-		res.attr_hash['force_unmount'] = '0'
+		res.addAttribute('force_unmount', '0')
 
 	if len(errors) > 1:
 		return [None, None, errors]
 	return [res, model, None]
 
 def addNfsc(request, form=None):
+	errors = list()
+
 	if form is None:
 		form = request.form
 
 	if not form:
-		luci_log.debug_verbose('addNfsc error: form is missing')
+		luci_log.debug_verbose('addNfsc0: form is missing')
 		return None
 
 	model = request.SESSION.get('model')
 	if not model:
-		luci_log.debug_verbose('addNfsc error: model is missing')
+		luci_log.debug_verbose('addNfsc1: model is missing')
 		return None
 
+	res = None
 	if form.has_key('edit'):
 		try:
 			oldname = form['oldname'].strip()
 			if not oldname:
-				raise KeyError, 'oldname is blank.'
-			res = getResourceForEdit(model, oldname)
+				raise Exception, 'oldname is blank'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e1:
+				errors.append('No NFS client resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug_verbose('addNfsc error: %s' % str(e))
-			return None
+			errors.append('No original name was found for this NFS client resource.')
+			luci_log.debug_verbose('addNfsc2: %s' % str(e))
 	else:
 		try:
 			res = NFSClient()
-		except:
-			luci_log.debug_verbose('addNfsc error: %s' % str(e))
-			return None
+			if not res:
+				raise Exception, 'res is None'
+		except Exception, e:
+			errors.append('An error occurred while creating a NFS client resource.')
+			luci_log.debug_verbose('addNfsc3: %s' % str(e))
 
 	if not res:
-		luci_log.debug_verbose('addNfsc error: res is none')
-		return None
+		return [None, None, errors]
 
-	errors = list()
+	# XXX: sanity check these fields
 	try:
 		name = form['resourceName'].strip()
 		if not name:
-			raise KeyError, 'resourceName is blank'
-		res.attr_hash['name'] = name
+			raise Exception, 'No name was given for this NFS client resource.'
+		res.addAttribute('name', name)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsc error: %s' % err)
+		luci_log.debug_verbose('addNfsc4: %s' % err)
 
 	try:
 		target = form['target'].strip()
-		res.attr_hash['target'] = target 
+		if not target:
+			raise Exception, 'No target was given for NFS client resource.'
+		res.addAttribute('target', target)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsc error: %s' % err)
+		luci_log.debug_verbose('addNfsc5: %s' % err)
 
 	try:
 		options = form['options'].strip()
-		res.attr_hash['options'] = options
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('options')
+		except:
+			pass
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsc error: %s' % err)
+		luci_log.debug_verbose('addNfsc6: %s' % err)
+
+	if form.has_key('allow_recover'):
+		res.addAttribute('allow_recover', '1')
+	else:
+		res.addAttribute('allow_recover', '0')
 
 	if len(errors) > 1:
 		return [None, None, errors]
 	return [res, model, None]
 
 def addNfsx(request, form=None):
+	errors = list()
+
 	if form is None:
 		form = request.form
 
 	if not form:
-		luci_log.debug_verbose('addNfsx error: model is missing')
+		luci_log.debug_verbose('addNfsx0: model is missing')
 		return None
 
 	model = request.SESSION.get('model')
 	if not model:
-		luci_log.debug_verbose('addNfsx error: model is missing')
+		luci_log.debug_verbose('addNfsx0: model is missing')
 		return None
 
+	res = None
 	if form.has_key('edit'):
 		try:
 			oldname = form['oldname'].strip()
 			if not oldname:
-				raise KeyError, 'oldname is blank.'
-			res = getResourceForEdit(model, oldname)
+				raise Exception, 'oldname is blank'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e1:
+				errors.append('No NFS export resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug_verbose('addNfsx error: %s', str(e))
-			return None
+			errors.append('No original name was found for this NFS export resource.')
+			luci_log.debug_verbose('addNfsx2: %s', str(e))
 	else:
 		try:
 			res = NFSExport()
-		except:
-			luci_log.debug_verbose('addNfsx error: %s', str(e))
-			return None
+			if not res:
+				raise Exception, 'res is None'
+		except Exception, e:
+			errors.append('An error occurred while creating a NFS clientresource.')
+			luci_log.debug_verbose('addNfsx3: %s', str(e))
 
 	if not res:
-		luci_log.debug_verbose('addNfsx error: res is None')
-		return None
+		return [None, None, errors]
 
-	errors = list()
 	try:
 		name = form['resourceName'].strip()
 		if not name:
-			raise KeyError, 'resourceName is blank'
-		res.attr_hash['name'] = name
+			raise Exception, 'No name was given for this NFS export resource.'
+		res.addAttribute('name', name)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addNfsx error: %s', err)
+		luci_log.debug_verbose('addNfsx4: %s' % err)
 
 	if len(errors) > 1:
 		return [None, None, errors]
 	return [res, model, None]
 
 def addScr(request, form=None):
+	errors = list()
+
 	if form is None:
 		form = request.form
 
 	if not form:
-		luci_log.debug_verbose('addScr error: form is missing')
+		luci_log.debug_verbose('addScr0: form is missing')
 		return None
 
 	model = request.SESSION.get('model')
 	if not model:
-		luci_log.debug_verbose('addScr error: model is missing')
+		luci_log.debug_verbose('addScr1: model is missing')
 		return None
 
+	res = None
 	if form.has_key('edit'):
 		try:
 			oldname = form['oldname'].strip()
 			if not oldname:
-				raise KeyError, 'oldname is blank.'
-			res = getResourceForEdit(model, oldname)
+				raise Exception, 'oldname is blank'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e1:
+				errors.append('No script resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug_verbose('addScr error: %s' % str(e))
-			return None
+			errors.append('No original name was found for this script resource.')
+			luci_log.debug_verbose('addScr2: %s' % str(e))
 	else:
 		try:
 			res = Script()
+			if not res:
+				raise Exception, 'res is None'
 		except Exception, e:
-			luci_log.debug_verbose('addScr error: %s' % str(e))
-			return None
+			errors.append('An error occurred while creating a script resource.')
+			luci_log.debug_verbose('addScr3: %s' % str(e))
 
 	if not res:
-		luci_log.debug_verbose('addScr error: res is None')
-		return None
+		return [None, None, errors]
 
-	errors = list()
 	try:
 		name = form['resourceName'].strip()
 		if not name:
-			raise KeyError, 'resourceName is blank'
-		res.attr_hash['name'] = name
+			raise Exception, 'No name was given for this script resource.'
+		res.addAttribute('name', name)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addScr error: %s' % err)
+		luci_log.debug_verbose('addScr4: %s' % err)
 
 	try:
 		path = form['file'].strip()
 		if not path:
-			raise KeyError, 'file path is blank'
-		res.attr_hash['file'] = path
+			raise Exception, 'No path to a script file was given for this script resource.'
+		res.addAttribute('file', path)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addScr error: %s' % err)
+		luci_log.debug_verbose('addScr5: %s' % err)
 
 	if len(errors) > 1:
 		return [None, None, errors]
 	return [res, model, None]
 
 def addSmb(request, form=None):
+	errors = list()
+
 	if form is None:
 		form = request.form
 
 	if not form:
-		luci_log.debug_verbose('addSmb error: form is missing')
+		luci_log.debug_verbose('addSmb0: form is missing')
 		return None
 
 	model = request.SESSION.get('model')
 	if not model:
-		luci_log.debug_verbose('addSmb error: model is missing')
+		luci_log.debug_verbose('addSmb1: model is missing')
 		return None
 
 	if form.has_key('edit'):
 		try:
 			oldname = form['oldname'].strip()
 			if not oldname:
-				raise KeyError, 'oldname is blank.'
-			res = getResourceForEdit(model, oldname)
+				raise Exception, 'oldname is blank'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e1:
+				errors.append('No Samba resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug_verbose('addSmb error: %s' % str(e))
-			return None
+			errors.append('No original name was found for this Samba resource.')
+			luci_log.debug_verbose('addSmb2: %s' % str(e))
 	else:
 		try:
 			res = Samba()
+			if not res:
+				raise Exception, 'res is None'
 		except Exception, e:
-			luci_log.debug_verbose('addSmb error: %s' % str(e))
-			return None
+			errors.append('An error occurred while creating a Samba resource.')
+			luci_log.debug_verbose('addSmb3: %s' % str(e))
 
 	if not res:
-		luci_log.debug_verbose('addSmb error: res is None')
-		return None
+		return [None, None, errors]
 
-	errors = list()
 	try:
 		name = form['resourceName'].strip()
 		if not name:
-			raise KeyError, 'resourceName is blank'
-		res.attr_hash['name'] = name
+			raise Exception, 'No name was given for this Samba resource.'
+		res.addAttribute('name', name)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addSmb error: %s' % err)
+		luci_log.debug_verbose('addSmb4: %s' % err)
 
 	try:
 		workgroup = form['workgroup'].strip()
-		res.attr_hash['workgroup'] = workgroup
+		if not workgroup:
+			raise Exception, 'No workgroup was given for this Samba resource.'
+		res.addAttribute('workgroup', workgroup)
 	except Exception, e:
 		err = str(e)
 		errors.append(err)
-		luci_log.debug_verbose('addSmb error: %s' % err)
+		luci_log.debug_verbose('addSmb5: %s' % err)
 
 	if len(errors) > 1:
 		return [None, None, errors]
 	return [res, model, None]
 
-resourceAddHandler = {
-	'ip': addIp,
-	'fs': addFs,
-	'gfs': addGfs,
-	'nfsm': addNfsm,
-	'nfsx': addNfsx,
-	'nfsc': addNfsc,
-	'scr': addScr,
-	'smb': addSmb
-}
-
-def resolveClusterChanges(self, clusterName, model):
-	try:
-		mb_nodes = model.getNodes()
-		if not mb_nodes or not len(mb_nodes):
-			raise Exception, 'node list is empty'
-	except Exception, e:
-		luci_log.debug_verbose('RCC0: no model builder nodes found for %s: %s' \
-				% (str(e), clusterName))
-		return 'Unable to find cluster nodes for %s' % clusterName
-
-	try:
-		cluster_node = self.restrictedTraverse(PLONE_ROOT + '/systems/cluster/' + clusterName)
-		if not cluster_node:
-			raise Exception, 'cluster node is none'
-	except Exception, e:
-		luci_log.debug('RCC1: cant find cluster node for %s: %s'
-			% (clusterName, str(e)))
-		return 'Unable to find an entry for %s in the Luci database.' % clusterName
-
-	try:
-		db_nodes = map(lambda x: x[0], cluster_node.objectItems('Folder'))
-		if not db_nodes or not len(db_nodes):
-			raise Exception, 'no database nodes'
-	except Exception, e:
-		# Should we just create them all? Can this even happen?
-		luci_log.debug('RCC2: error: %s' % str(e))
-		return 'Unable to find database entries for any nodes in %s' % clusterName
+def addApache(request, form=None):
+	errors = list()
 
-	same_host = lambda x, y: x == y or x[:len(y) + 1] == y + '.' or y[:len(x) + 1] == x + '.'
+	if form is None:
+		form = request.form
 
-	# this is a really great algorithm.
-	missing_list = list()
-	new_list = list()
-	for i in mb_nodes:
-		for j in db_nodes:
-			f = 0
-			if same_host(i, j):
-				f = 1
-				break
-		if not f:
-			new_list.append(i)
+	if not form:
+		luci_log.debug_verbose('addApache0: form is missing')
+		return None
 
-	for i in db_nodes:
-		for j in mb_nodes:
-			f = 0
-			if same_host(i, j):
-				f = 1
-				break
-		if not f:
-			missing_list.append(i)
+	model = request.SESSION.get('model')
+	if not model:
+		luci_log.debug_verbose('addApache1: model is missing')
+		return None
 
-	messages = list()
-	for i in missing_list:
+	res = None
+	if form.has_key('edit'):
 		try:
-			## or alternately
-			##new_node = cluster_node.restrictedTraverse(i)
-			##setNodeFlag(self, new_node, CLUSTER_NODE_NOT_MEMBER)
-			cluster_node.delObjects([i])
-			messages.append('Node \"%s\" is no longer in a member of cluster \"%s\." It has been deleted from the management interface for this cluster.' % (i, clusterName))
-			luci_log.debug_verbose('VCC3: deleted node %s' % i)
+			oldname = form['oldname'].strip()
+			if not oldname:
+				raise Exception, 'oldname is blank.'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e:
+				errors.append('No Apache resource named \"%s\" exists.' % oldname)
 		except Exception, e:
-			luci_log.debug_verbose('VCC4: delObjects: %s: %s' % (i, str(e)))
-
-	new_flags = CLUSTER_NODE_NEED_AUTH | CLUSTER_NODE_ADDED
-	for i in new_list:
+			errors.append('No original name was found for this Apache resource.')
+			luci_log.debug_verbose('addApache2: %s' % str(e))
+	else:
 		try:
-			cluster_node.manage_addFolder(i, '__luci__:csystem:' + clusterName)
-			new_node = cluster_node.restrictedTraverse(i)
-			setNodeFlag(self, new_node, new_flags)
-			messages.append('A new cluster node, \"%s,\" is now a member of cluster \"%s.\" It has been added to the management interface for this cluster, but you must authenticate to it in order for it to be fully functional.' % (i, clusterName))
+			res = Apache()
+			if not res:
+				raise Exception, 'could not create Apache object'
 		except Exception, e:
-			messages.append('A new cluster node, \"%s,\" is now a member of cluster \"%s,\". but it has not been added to the management interface for this cluster as a result of an error creating a database entry for it.' % (i, clusterName))
-			luci_log.debug_verbose('VCC5: addFolder: %s/%s: %s' \
-				% (clusterName, i, str(e)))
-	
-	return messages
+			errors.append('An error occurred while creating an Apache resource.')
+			luci_log.debug_verbose('addApache3: %s' % str(e))
 
-def addResource(self, request, model, res, res_type):
-	clustername = model.getClusterName()
-	if not clustername:
-		luci_log.debug_verbose('addResource0: no cluname from mb')
-		return 'Unable to determine cluster name'
+	if not res:
+		return [None, None, errors]
 
-	rc = getRicciAgent(self, clustername)
-	if not rc:
-		luci_log.debug_verbose('addResource1: unable to find a ricci agent for cluster %s' % clustername)
-		return 'Unable to find a ricci agent for the %s cluster' % clustername
+	try:
+		name = form['resourceName'].strip()
+		if not name:
+			raise Exception, 'No name was given for this Apache resource.'
+		res.addAttribute('name', name)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addApache4: %s' % err)
 
 	try:
-		model.getResourcesPtr().addChild(res)
+		server_root = form['server_root'].strip()
+		if not server_root:
+			raise KeyError, 'No server root was given for this Apache resource.'
+		res.addAttribute('server_root', server_root)
 	except Exception, e:
-		luci_log.debug_verbose('addResource2: adding the new resource failed: %s' % str(e))
-		return 'Unable to add the new resource'
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addApache5: %s' % err)
 
 	try:
-		cp = model.getClusterPtr()
-		cp.incrementConfigVersion()
-		model.setModified(True)
-		conf = model.exportModelAsString()
-		if not conf:
-			raise Exception, 'model string for %s is blank' % clustername
+		config_file = form['config_file'].strip()
+		if not server_root:
+			raise KeyError, 'No path to the Apache configuration file was given.'
+		res.addAttribute('config_file', config_file)
 	except Exception, e:
-		luci_log.debug_verbose('addResource3: exportModelAsString : %s' \
-			% str(e))
-		return 'An error occurred while adding this resource'
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addApache6: %s' % err)
 
 	try:
-		ragent = rc.hostname()
+		options = form['httpd_options'].strip()
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('httpd_options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('httpd_options')
+		except:
+			pass
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addApache7: %s' % err)
+
+	try:
+		shutdown_wait = int(form['shutdown_wait'].strip())
+		res.addAttribute('shutdown_wait', shutdown_wait)
+	except KeyError, e:
+		res.addAttribute('shutdown_wait', 0)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addApache7: %s' % err)
+
+	if len(errors) > 1:
+		return [None, None, errors]
+	return [res, model, None]
+
+def addMySQL(request, form=None):
+	errors = list()
+
+	if form is None:
+		form = request.form
+
+	if not form:
+		luci_log.debug_verbose('addMySQL0: form is missing')
+		return None
+
+	model = request.SESSION.get('model')
+	if not model:
+		luci_log.debug_verbose('addMySQL1: model is missing')
+		return None
+
+	res = None
+	if form.has_key('edit'):
+		try:
+			oldname = form['oldname'].strip()
+			if not oldname:
+				raise Exception, 'oldname is blank.'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e:
+				errors.append('No MySQL resource named \"%s\" exists.' % oldname)
+		except Exception, e:
+			errors.append('No original name was found for this MySQL resource.')
+			luci_log.debug_verbose('addMySQL2: %s' % str(e))
+	else:
+		try:
+			res = MySQL()
+			if not res:
+				raise Exception, 'could not create MySQL object'
+		except Exception, e:
+			errors.append('An error occurred while creating a MySQL resource.')
+			luci_log.debug_verbose('addMySQL3: %s' % str(e))
+
+	if not res:
+		return [None, None, errors]
+
+	try:
+		name = form['resourceName'].strip()
+		if not name:
+			raise Exception, 'No name was given for this MySQL resource.'
+		res.addAttribute('name', name)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addMySQL4: %s' % err)
+
+	try:
+		config_file = form['config_file'].strip()
+		if not config_file:
+			raise KeyError, 'No path to the MySQL configuration file was given.'
+		res.addAttribute('config_file', config_file)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addMySQL5: %s' % err)
+
+	try:
+		listen_addr = form['listen_address'].strip()
+		if not listen_addr:
+			raise KeyError, 'No address was given for MySQL server to listen on.'
+		res.addAttribute('listen_address', listen_addr)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addMySQL6: %s' % err)
+
+	try:
+		options = form['mysql_options'].strip()
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('mysql_options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('mysql_options')
+		except:
+			pass
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addMySQL7: %s' % err)
+
+	try:
+		shutdown_wait = int(form['shutdown_wait'].strip())
+		res.addAttribute('shutdown_wait', shutdown_wait)
+	except KeyError, e:
+		res.addAttribute('shutdown_wait', 0)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addMySQL7: %s' % err)
+
+	if len(errors) > 1:
+		return [None, None, errors]
+	return [res, model, None]
+
+def addOpenLDAP(request, form=None):
+	errors = list()
+
+	if form is None:
+		form = request.form
+
+	if not form:
+		luci_log.debug_verbose('addOpenLDAP0: form is missing')
+		return None
+
+	model = request.SESSION.get('model')
+	if not model:
+		luci_log.debug_verbose('addOpenLDAP1: model is missing')
+		return None
+
+	res = None
+	if form.has_key('edit'):
+		try:
+			oldname = form['oldname'].strip()
+			if not oldname:
+				raise Exception, 'oldname is blank.'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e:
+				errors.append('No OpenLDAP resource named \"%s\" exists.' % oldname)
+		except Exception, e:
+			errors.append('No original name was found for this OpenLDAP resource.')
+			luci_log.debug_verbose('addOpenLDAP2: %s' % str(e))
+	else:
+		try:
+			res = OpenLDAP()
+			if not res:
+				raise Exception, 'could not create OpenLDAP object'
+		except Exception, e:
+			errors.append('An error occurred while creating an OpenLDAP resource.')
+			luci_log.debug_verbose('addOpenLDAP3: %s' % str(e))
+
+	if not res:
+		return [None, None, errors]
+
+	try:
+		name = form['resourceName'].strip()
+		if not name:
+			raise Exception, 'No name was given for this OpenLDAP resource.'
+		res.addAttribute('name', name)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addOpenLDAP4: %s' % err)
+
+	try:
+		url_list = form['url_list'].strip()
+		if not url_list:
+			raise KeyError, 'No URL list was given for this OpenLDAP resource.'
+		res.addAttribute('url_list', url_list)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addOpenLDAP5: %s' % err)
+
+	try:
+		config_file = form['config_file'].strip()
+		if not config_file:
+			raise KeyError, 'No path to the OpenLDAP configuration file was given.'
+		res.addAttribute('config_file', config_file)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addOpenLDAP6: %s' % err)
+
+	try:
+		options = form['slapd_options'].strip()
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('slapd_options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('slapd_options')
+		except:
+			pass
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addOpenLDAP7: %s' % err)
+
+	try:
+		shutdown_wait = int(form['shutdown_wait'].strip())
+		res.addAttribute('shutdown_wait', shutdown_wait)
+	except KeyError, e:
+		res.addAttribute('shutdown_wait', 0)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addOpenLDAP7: %s' % err)
+
+	if len(errors) > 1:
+		return [None, None, errors]
+	return [res, model, None]
+
+def addPostgres8(request, form=None):
+	errors = list()
+
+	if form is None:
+		form = request.form
+
+	if not form:
+		luci_log.debug_verbose('addPostgreSQL80: form is missing')
+		return None
+
+	model = request.SESSION.get('model')
+	if not model:
+		luci_log.debug_verbose('addPostgreSQL81: model is missing')
+		return None
+
+	res = None
+	if form.has_key('edit'):
+		try:
+			oldname = form['oldname'].strip()
+			if not oldname:
+				raise Exception, 'oldname is blank.'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e:
+				errors.append('No PostgreSQL 8 resource named \"%s\" exists.' % oldname)
+		except Exception, e:
+			errors.append('No original name was found for this PostgreSQL 8 resource.')
+			luci_log.debug_verbose('addPostgreSQL82: %s' % str(e))
+	else:
+		try:
+			res = Postgres8()
+			if not res:
+				raise Exception, 'could not create PostgreSQL 8 object'
+		except Exception, e:
+			errors.append('An error occurred while creating a PostgreSQL 8 resource.')
+			luci_log.debug_verbose('addPostgreSQL83: %s' % str(e))
+
+	if not res:
+		return [None, None, errors]
+
+	try:
+		name = form['resourceName'].strip()
+		if not name:
+			raise Exception, 'No name was given for this PostgreSQL 8 resource.'
+		res.addAttribute('name', name)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addPostgreSQL84: %s' % err)
+
+	try:
+		user = form['postmaster_user'].strip()
+		if not user:
+			raise KeyError, 'No postmaster user was given for this PostgreSQL 8 resource.'
+		res.addAttribute('postmaster_user', user)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addPostgreSQL85: %s' % err)
+
+	try:
+		config_file = form['config_file'].strip()
+		if not config_file:
+			raise KeyError, 'No path to the PostgreSQL 8 configuration file was given.'
+		res.addAttribute('config_file', config_file)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addPostgreSQL86: %s' % err)
+
+	try:
+		options = form['postmaster_options'].strip()
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('postmaster_options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('postmaster_options')
+		except:
+			pass
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addPostgreSQL87: %s' % err)
+
+	try:
+		shutdown_wait = int(form['shutdown_wait'].strip())
+		res.addAttribute('shutdown_wait', shutdown_wait)
+	except KeyError, e:
+		res.addAttribute('shutdown_wait', 0)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addPostgreSQL87: %s' % err)
+
+	if len(errors) > 1:
+		return [None, None, errors]
+	return [res, model, None]
+
+def addTomcat5(request, form=None):
+	errors = list()
+
+	if form is None:
+		form = request.form
+
+	if not form:
+		luci_log.debug_verbose('addTomcat50: form is missing')
+		return None
+
+	model = request.SESSION.get('model')
+	if not model:
+		luci_log.debug_verbose('addTomcat51: model is missing')
+		return None
+
+	res = None
+	if form.has_key('edit'):
+		try:
+			oldname = form['oldname'].strip()
+			if not oldname:
+				raise Exception, 'oldname is blank.'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e:
+				errors.append('No Tomcat 5 resource named \"%s\" exists.' % oldname)
+		except Exception, e:
+			errors.append('No original name was found for this Tomcat 5 resource.')
+			luci_log.debug_verbose('addTomcat52: %s' % str(e))
+	else:
+		try:
+			res = Tomcat5()
+			if not res:
+				raise Exception, 'could not create Tomcat5 object'
+		except Exception, e:
+			errors.append('An error occurred while creating a Tomcat 5 resource.')
+			luci_log.debug_verbose('addTomcat53: %s' % str(e))
+
+	if not res:
+		return [None, None, errors]
+
+	try:
+		name = form['resourceName'].strip()
+		if not name:
+			raise Exception, 'No name was given for this Tomcat 5 resource.'
+		res.addAttribute('name', name)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addTomcat54: %s' % err)
+
+	try:
+		user = form['tomcat_user'].strip()
+		if not user:
+			raise KeyError, 'No user was given for this Tomcat 5 resource.'
+		res.addAttribute('tomcat_user', user)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addTomcat55: %s' % err)
+
+	try:
+		config_file = form['config_file'].strip()
+		if not config_file:
+			raise KeyError, 'No path to the Tomcat 5 configuration file was given.'
+		res.addAttribute('config_file', config_file)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addTomcat56: %s' % err)
+
+	try:
+		options = form['catalina_options'].strip()
+		if not options:
+			raise KeyError, 'no options'
+		res.addAttribute('catalina_options', options)
+	except KeyError, e:
+		try:
+			res.removeAttribute('catalina_options')
+		except:
+			pass
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addTomcat57: %s' % err)
+
+	try:
+		catalina_base = form['catalina_base'].strip()
+		if not catalina_base:
+			raise KeyError, 'No cataliny base directory was given for this Tomcat 5 resource.'
+		res.addAttribute('catalina_base', catalina_base)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addTomcat58: %s' % err)
+
+	try:
+		shutdown_wait = int(form['shutdown_wait'].strip())
+		res.addAttribute('shutdown_wait', shutdown_wait)
+	except KeyError, e:
+		res.addAttribute('shutdown_wait', 0)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addTomcat59: %s' % err)
+
+	if len(errors) > 1:
+		return [None, None, errors]
+	return [res, model, None]
+
+def addVM(request, form=None):
+	errors = list()
+
+	if form is None:
+		form = request.form
+
+	if not form:
+		luci_log.debug_verbose('addVM0: form is missing')
+		return None
+
+	model = request.SESSION.get('model')
+	if not model:
+		luci_log.debug_verbose('addVM1: model is missing')
+		return None
+
+	res = None
+	if form.has_key('edit'):
+		try:
+			oldname = form['oldname'].strip()
+			if not oldname:
+				raise Exception, 'oldname is blank.'
+			try:
+				res = getResourceForEdit(model, oldname)
+			except KeyError, e:
+				errors.append('No VM resource named \"%s\" exists.' % oldname)
+		except Exception, e:
+			errors.append('No original name was found for this VM resource.')
+			luci_log.debug_verbose('addVM2: %s' % str(e))
+	else:
+		try:
+			res = Vm()
+			if not res:
+				raise Exception, 'could not create VM object'
+		except Exception, e:
+			errors.append('An error occurred while creating an VM resource.')
+			luci_log.debug_verbose('addVM3: %s' % str(e))
+
+	if not res:
+		return [None, None, errors]
+
+	try:
+		name = form['resourceName'].strip()
+		if not name:
+			raise Exception, 'No name was given for this VM resource.'
+		res.addAttribute('name', name)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM4: %s' % err)
+
+	try:
+		domain = form['domain'].strip()
+		if not domain:
+			raise KeyError, 'No domain was given for this VM resource.'
+		res.addAttribute('domain', domain)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM5: %s' % err)
+
+	try:
+		bootloader = form['bootloader'].strip()
+		if not bootloader:
+			raise KeyError, 'No bootloader was given for this VM resource.'
+		res.addAttribute('bootloader', bootloader)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM6: %s' % err)
+
+	try:
+		path = form['path'].strip()
+		if not path:
+			raise KeyError, 'No path specification was given for this VM resource.'
+		res.addAttribute('path', path)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM7: %s' % err)
+
+	try:
+		disk = form['rootdisk_physical'].strip()
+		if not disk:
+			raise KeyError, 'No physical root disk was given for this VM resource.'
+		res.addAttribute('rootdisk_physical', disk)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM8: %s' % err)
+
+	try:
+		disk = form['rootdisk_virtual'].strip()
+		if not disk:
+			raise KeyError, 'No virtual root disk was given for this VM resource.'
+		res.addAttribute('rootdisk_virtual', disk)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM9: %s' % err)
+
+	try:
+		disk = form['swapdisk_physical'].strip()
+		if not disk:
+			raise KeyError, 'No physical swap disk was given for this VM resource.'
+		res.addAttribute('swapdisk_physical', disk)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM10: %s' % err)
+
+	try:
+		disk = form['swapdisk_virtual'].strip()
+		if not disk:
+			raise KeyError, 'No virtual swap disk was given for this VM resource.'
+		res.addAttribute('swapdisk_virtual', disk)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM11: %s' % err)
+
+	try:
+		vif = form['vif'].strip()
+		if not vif:
+			raise KeyError, 'No virtual interface MAC address was given for this VM resource.'
+		res.addAttribute('vif', vif)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM12: %s' % err)
+
+	try:
+		memsize = int(form['memory'].strip())
+		res.addAttribute('memory', memsize)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM13: %s' % err)
+
+	try:
+		recovery = form['recovery'].lower().strip()
+		if not recovery:
+			raise Exception, 'No recovery method was given for this VM resource.'
+		if recovery != 'restart' and recovery != 'relocate' and recovery != 'disable':
+			raise Exception, 'An invalid recovery type, \"%s\", was given for this VM resource.' % recovery
+		res.addAttribute('recovery', recovery)
+	except Exception, e:
+		err = str(e)
+		errors.append(err)
+		luci_log.debug_verbose('addVM14: %s' % err)
+
+	if len(errors) > 1:
+		return [None, None, errors]
+	return [res, model, None]
+
+resourceAddHandler = {
+	'ip': addIp,
+	'fs': addFs,
+	'gfs': addGfs,
+	'nfsm': addNfsm,
+	'nfsx': addNfsx,
+	'nfsc': addNfsc,
+	'scr': addScr,
+	'smb': addSmb,
+	'vm': addVM,
+	'tomcat-5': addTomcat5,
+	'postgres-8': addPostgres8,
+	'apache': addApache,
+	'openldap': addOpenLDAP,
+	'mysql': addMySQL
+}
+
+def resolveClusterChanges(self, clusterName, model):
+	try:
+		mb_nodes = model.getNodes()
+		if not mb_nodes or not len(mb_nodes):
+			raise Exception, 'node list is empty'
+	except Exception, e:
+		luci_log.debug_verbose('RCC0: no model builder nodes found for %s: %s' \
+				% (str(e), clusterName))
+		return 'Unable to find cluster nodes for %s' % clusterName
+
+	try:
+		cluster_node = self.restrictedTraverse(PLONE_ROOT + '/systems/cluster/' + clusterName)
+		if not cluster_node:
+			raise Exception, 'cluster node is none'
+	except Exception, e:
+		luci_log.debug('RCC1: cant find cluster node for %s: %s'
+			% (clusterName, str(e)))
+		return 'Unable to find an entry for %s in the Luci database.' % clusterName
+
+	try:
+		db_nodes = map(lambda x: x[0], cluster_node.objectItems('Folder'))
+		if not db_nodes or not len(db_nodes):
+			raise Exception, 'no database nodes'
+	except Exception, e:
+		# Should we just create them all? Can this even happen?
+		luci_log.debug('RCC2: error: %s' % str(e))
+		return 'Unable to find database entries for any nodes in %s' % clusterName
+
+	same_host = lambda x, y: x == y or x[:len(y) + 1] == y + '.' or y[:len(x) + 1] == x + '.'
+
+	# this is a really great algorithm.
+	missing_list = list()
+	new_list = list()
+	for i in mb_nodes:
+		for j in db_nodes:
+			f = 0
+			if same_host(i, j):
+				f = 1
+				break
+		if not f:
+			new_list.append(i)
+
+	for i in db_nodes:
+		for j in mb_nodes:
+			f = 0
+			if same_host(i, j):
+				f = 1
+				break
+		if not f:
+			missing_list.append(i)
+
+	messages = list()
+	for i in missing_list:
+		try:
+			## or alternately
+			##new_node = cluster_node.restrictedTraverse(i)
+			##setNodeFlag(self, new_node, CLUSTER_NODE_NOT_MEMBER)
+			cluster_node.delObjects([i])
+			messages.append('Node \"%s\" is no longer in a member of cluster \"%s\." It has been deleted from the management interface for this cluster.' % (i, clusterName))
+			luci_log.debug_verbose('VCC3: deleted node %s' % i)
+		except Exception, e:
+			luci_log.debug_verbose('VCC4: delObjects: %s: %s' % (i, str(e)))
+
+	new_flags = CLUSTER_NODE_NEED_AUTH | CLUSTER_NODE_ADDED
+	for i in new_list:
+		try:
+			cluster_node.manage_addFolder(i, '__luci__:csystem:' + clusterName)
+			new_node = cluster_node.restrictedTraverse(i)
+			setNodeFlag(self, new_node, new_flags)
+			messages.append('A new cluster node, \"%s,\" is now a member of cluster \"%s.\" It has been added to the management interface for this cluster, but you must authenticate to it in order for it to be fully functional.' % (i, clusterName))
+		except Exception, e:
+			messages.append('A new cluster node, \"%s,\" is now a member of cluster \"%s,\". but it has not been added to the management interface for this cluster as a result of an error creating a database entry for it.' % (i, clusterName))
+			luci_log.debug_verbose('VCC5: addFolder: %s/%s: %s' \
+				% (clusterName, i, str(e)))
+
+	return messages
+
+def addResource(self, request, model, res, res_type):
+	clustername = model.getClusterName()
+	if not clustername:
+		luci_log.debug_verbose('addResource0: no cluname from mb')
+		return 'Unable to determine cluster name'
+
+	rc = getRicciAgent(self, clustername)
+	if not rc:
+		luci_log.debug_verbose('addResource1: unable to find a ricci agent for cluster %s' % clustername)
+		return 'Unable to find a ricci agent for the %s cluster' % clustername
+
+	try:
+		model.getResourcesPtr().addChild(res)
+	except Exception, e:
+		luci_log.debug_verbose('addResource2: adding the new resource failed: %s' % str(e))
+		return 'Unable to add the new resource'
+
+	try:
+		cp = model.getClusterPtr()
+		cp.incrementConfigVersion()
+		model.setModified(True)
+		conf = model.exportModelAsString()
+		if not conf:
+			raise Exception, 'model string for %s is blank' % clustername
+	except Exception, e:
+		luci_log.debug_verbose('addResource3: exportModelAsString : %s' \
+			% str(e))
+		return 'An error occurred while adding this resource'
+
+	try:
+		ragent = rc.hostname()
 		if not ragent:
 			luci_log.debug_verbose('addResource4: missing ricci hostname')
 			raise Exception, 'unknown ricci agent hostname'
@@ -6049,7 +6820,7 @@
 		request.SESSION.set('model', model)
 	except:
 		luci_log.debug_verbose('Appending model to request failed')
-		return 'An error occurred while storing the cluster model.' 
+		return 'An error occurred while storing the cluster model.'
 
 def resolve_nodename(self, clustername, nodename):
 	path = str(CLUSTER_FOLDER_PATH + clustername)
@@ -6206,7 +6977,7 @@
 			msg += 'Fix the error and try again:\n'
 		else:
 			msg += 'PASSED\n'
-			
+
 			msg += 'Making sure no clustername change has accured - '
 			new_name = cc_xml.firstChild.getAttribute('name')
 			if new_name != clustername:
@@ -6214,13 +6985,13 @@
 				msg += 'Fix the error and try again:\n'
 			else:
 				msg += 'PASSED\n'
-				
+
 				msg += 'Increasing cluster version number - '
 				version = cc_xml.firstChild.getAttribute('config_version')
 				version = int(version) + 1
 				cc_xml.firstChild.setAttribute('config_version', str(version))
 				msg += 'DONE\n'
-				
+
 				msg += 'Propagating new cluster.conf'
 				rc = getRicciAgent(self, clustername)
 				if not rc:
@@ -6231,7 +7002,7 @@
 					if batch_id is None or result is None:
 						luci_log.debug_verbose('VFA: setClusterConf: batchid or result is None')
 						msg += '\nUnable to propagate the new cluster configuration for ' + clustername + '\n\n'
-					else:	
+					else:
 						msg += ' - DONE\n'
 						cc = cc_xml.toxml()
 						msg += '\n\nALL DONE\n\n'


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]