cluster-devel.redhat.com archive mirror
 help / color / mirror / Atom feed
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2007-02-23 22:07 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2007-02-23 22:07 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe at sourceware.org	2007-02-23 22:07:45

Modified files:
	luci/cluster   : form-chooser form-macros 
	luci/homebase  : luci_homebase.css 
	luci/site/luci/Extensions: cluster_adapters.py 
	                           conga_constants.py ricci_bridge.py 
Added files:
	luci/cluster   : validate_sys_svc.js 
	luci/plone-custom: conga_ajax.js svc_reload.png 
	                   svc_reload_active.png svc_reload_disabled.png 
	                   svc_start.png svc_start_active.png 
	                   svc_start_disabled.png svc_stop.png 
	                   svc_stop_active.png svc_stop_disabled.png 
	luci/site/luci/Extensions: system_adapters.py 

Log message:
	- System service management interface (chkconfig / service start/stop/restart)

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/validate_sys_svc.js.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&r1=1.16&r2=1.17
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&r1=1.192&r2=1.193
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/homebase/luci_homebase.css.diff?cvsroot=cluster&r1=1.39&r2=1.40
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/conga_ajax.js.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_reload.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_reload_active.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_reload_disabled.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_start.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_start_active.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_start_disabled.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_stop.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_stop_active.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/svc_stop_disabled.png.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/system_adapters.py.diff?cvsroot=cluster&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.243&r2=1.244
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&r1=1.36&r2=1.37
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/ricci_bridge.py.diff?cvsroot=cluster&r1=1.58&r2=1.59

/cvs/cluster/conga/luci/cluster/validate_sys_svc.js,v  -->  standard output
revision 1.1
--- conga/luci/cluster/validate_sys_svc.js
+++ -	2007-02-23 22:07:45.984856000 +0000
@@ -0,0 +1,22 @@
+function svc_callback() {
+	if (xmlHttp_object.readyState == 4) {
+		if (xmlHttp_object.status == 200) {
+			var response = xmlHttp_object.responseXML;
+			if (response) {
+				req_status = response.getAttribute('success');
+				req_op = response.getAttribute('operation');
+				req_svc = response.getAttribute('service');
+				req_msg = response.getAttribute('message');
+				//alert(req_msg + ' / ' + req_status + ' / ' + req_op + ' / ' + req_svc);
+			} else {
+				alert(xmlHttp_object.responseText);
+			}
+		} else {
+			//alert('Error retrieving data from server: ' + xmlHttp_object.status);
+		}
+	}
+}
+
+function update_sys_svc(url) {
+	initiate_async_get(url, svc_callback);
+}
--- conga/luci/cluster/form-chooser	2007/02/01 20:27:33	1.16
+++ conga/luci/cluster/form-chooser	2007/02/23 22:07:45	1.17
@@ -149,11 +149,15 @@
     <span tal:omit-tag="" tal:condition="python: ptype == '55'">
      <div metal:use-macro="here/form-macros/macros/fencedevprocess-form"/>
     </span>
-
     <span tal:omit-tag="" tal:condition="python: ptype == '80'">
      <div metal:use-macro="here/form-macros/macros/conf_editor-form"/>
     </span>
-
+    <span tal:omit-tag="" tal:condition="python: ptype == '90'">
+     <div metal:use-macro="here/form-macros/macros/system-svc-form"/>
+    </span>
+    <span tal:omit-tag="" tal:condition="python: ptype == '91'">
+     <div metal:use-macro="here/form-macros/macros/system-svc-update-form"/>
+    </span>
    </span>
   </metal:choose-form>
   </body>
--- conga/luci/cluster/form-macros	2007/02/20 23:06:59	1.192
+++ conga/luci/cluster/form-macros	2007/02/23 22:07:45	1.193
@@ -5022,10 +5022,110 @@
 	</div>
 </div>
 
+
 <div metal:define-macro="fencedevprocess-form">
 	<h2>Fence Device Process Form</h2>
 </div>
 
+<div metal:define-macro="system-svc-form">
+	<script type="text/javascript"
+		src="conga_ajax.js">
+	</script>
+	<script type="text/javascript"
+		src="/luci/cluster/validate_sys_svc.js">
+	</script>
+	<h2>Configure System Services</h2>
+
+	<form name="svcform" method="post" action="">
+
+	<input type="hidden" name="pagetype"
+		tal:attributes="value request/pagetype | nothing" />
+
+	<input type="hidden" name="systemname"
+		tal:attributes="value request/systemname | nothing" />
+
+	<table class="systemsTable"
+		tal:define="svcinfo python:'systemname' in request and here.get_sys_svc_list(request, request['systemname']) or []">
+		<tr class="systemsTable">
+			<th class="systemsTable">Name</th>
+			<th class="systemsTable">State</th>
+			<th class="systemsTable">Enabled at boot</th>
+			<th></th>
+		</tr>
+
+		<tr tal:repeat="s svcinfo">
+			<td class="systemsTable">
+				<span tal:content="s/name |string:[unknown]"
+					tal:attributes="title s/desc | nothing" />
+			</td>
+
+			<td class="systemsTable">
+				<span
+					tal:content="s/state |string:[unknown]"
+					tal:attributes="id python: '__STATUS__:' + s['name']" />
+			</td>
+
+			<td class="systemsTable">
+				<input type="checkbox"
+					tal:attributes="
+						name s/name;
+						id s/name;
+						checked python: s['enabled'] and 'checked' or ''"
+				/>
+			</td>
+
+			<td class="systemsTable"
+				tal:define="
+					restart_disabled python:not s['running'] and 'disabled' or '';
+					start_disabled python:s['running'] and 'disabled' or '';
+					stop_disabled python:not s['running'] and 'disabled' or ''">
+
+				<input type="button"
+					title="start this service"
+					class="svc_control svc_control_start"
+					onfocus="if (this.blur) this.blur()"
+					tal:attributes="
+						onclick python: 'update_sys_svc(\'' + s['starturl'] + '\')';
+						id python: '__START__' + s['name'];
+						name python: '__START__' + s['name'];
+						disabled start_disabled" />
+
+				<input type="button"
+					title="restart this service"
+					class="svc_control svc_control_restart"
+					onfocus="if (this.blur) this.blur()"
+					tal:attributes="
+						onclick python: 'update_sys_svc(\'' + s['restarturl'] + '\')';
+						id python: '__RESTART__' + s['name'];
+						name python: '__RESTART__' + s['name'];
+						disabled restart_disabled" />
+
+				<input type="button"
+					title="stop this service"
+					class="svc_control svc_control_stop"
+					onfocus="if (this.blur) this.blur()"
+					tal:attributes="
+						onclick python: 'update_sys_svc(\'' + s['stopurl'] + '\')';
+						id python: '__STOP__' + s['name'];
+						name python: '__STOP__' + s['name'];
+						disabled stop_disabled" />
+			</td>
+		</tr>
+		<tr class="systemsTable">
+			<td>
+				<div class="hbSubmit">
+					<input type="submit" value="Update" />
+				</div>
+			</td>
+		</tr>
+	</table>
+	</form>
+</div>
+
+<div metal:define-macro="system-svc-update-form">
+	<tal:block tal:define="ret python: here.validate_manage_svc(request)" />
+</div>
+
 <div metal:define-macro="conf_editor-form">
 	<h2>Edit cluster.conf</h2>
 	<form method="post"
--- conga/luci/homebase/luci_homebase.css	2007/02/08 05:05:22	1.39
+++ conga/luci/homebase/luci_homebase.css	2007/02/23 22:07:45	1.40
@@ -8,6 +8,60 @@
 	font-size: 12px;
 }
 
+input[type=image] {
+	border: 0;
+	background: transparent;
+	padding-left: +.3333em;
+	padding-right: +.3333em;
+}
+
+input[type=image]:disabled {
+	cursor: url('cursor-disabled.png'), default;
+}
+
+input.svc_control {
+	color: transparent ! important;
+	border: none ! important;
+	outline: hidden ! important;
+	background-color: transparent ! important;
+	background-repeat: no-repeat ! important;
+	cursor: pointer;
+}
+
+.svc_control_start {
+	background-image: url(svc_start.png);
+}
+
+input.svc_control_start:hover, input.svc_control_start:active {
+	background-image: url(svc_start_active.png) ! important;
+}
+input.svc_control_start:disabled {
+	background-image: url(svc_start_disabled.png) ! important;
+	cursor: url('cursor-disabled.png'), default;
+}
+
+input.svc_control_restart {
+	background-image: url(svc_reload.png);
+}
+input.svc_control_restart:hover, input.svc_control_restart:active {
+	background-image: url(svc_reload_active.png) ! important;
+}
+input.svc_control_restart:disabled {
+	background-image: url(svc_reload_disabled.png) ! important;
+	cursor: url('cursor-disabled.png'), default;
+}
+
+input.svc_control_stop {
+	background-image: url(svc_stop.png);
+}
+input.svc_control_stop:hover, input.svc_control_stop:active {
+	background-image: url(svc_stop_active.png) ! important;
+}
+input.svc_control_stop:disabled {
+	background-image: url(svc_stop_disabled.png) ! important;
+	cursor: url('cursor-disabled.png'), default;
+}
+
 input[type=checkbox], input[type=radio] {
 	float: left ! important;
 	vertical-align: middle;
/cvs/cluster/conga/luci/plone-custom/conga_ajax.js,v  -->  standard output
revision 1.1
--- conga/luci/plone-custom/conga_ajax.js
+++ -	2007-02-23 22:07:46.355394000 +0000
@@ -0,0 +1,29 @@
+var xmlHttp_object = false;
+
+function initiate_async_get(url, callback_function) {
+	xmlHttp_object = false;
+
+	if (!xmlHttp_object && typeof XMLHttpRequest != 'undefined') {
+		try {
+			xmlHttp_object = new XMLHttpRequest();
+		} catch (e0) {
+			try {
+				xmlHttp_object = new ActiveXObject("Msxml2.XMLHTTP");
+			} catch (e) {
+				try {
+					xmlHttp_object = new ActiveXObject("Microsoft.XMLHTTP");
+				} catch (e2) {
+					xmlHttp_object = false;
+				}
+			}
+		}
+	}
+
+	if (xmlHttp_object) {
+		xmlHttp_object.open("GET", url, true);
+		xmlHttp_object.onreadystatechange = callback_function;
+		xmlHttp_object.send(null);
+	} else {
+		alert("Unable to communicate with the luci server.");
+	}
+}
/cvs/cluster/conga/luci/plone-custom/svc_reload.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_reload.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_reload_active.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_reload_active.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_reload_disabled.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_reload_disabled.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_start.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_start.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_start_active.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_start_active.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_start_disabled.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_start_disabled.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_stop.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_stop.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_stop_active.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_stop_active.png and - differ
/cvs/cluster/conga/luci/plone-custom/svc_stop_disabled.png,v  -->  standard output
revision 1.1
Binary files /cvs/cluster/conga/luci/plone-custom/svc_stop_disabled.png and - differ
/cvs/cluster/conga/luci/site/luci/Extensions/system_adapters.py,v  -->  standard output
revision 1.1
--- conga/luci/site/luci/Extensions/system_adapters.py
+++ -	2007-02-23 22:07:47.286199000 +0000
@@ -0,0 +1,134 @@
+from ricci_communicator import RicciCommunicator
+from ricci_bridge import list_services, updateServices, svc_manage
+from LuciSyslog import LuciSyslog
+
+try: 
+	luci_log = LuciSyslog()
+except:
+	pass
+
+def get_sys_svc_list(self, request, hostname):
+	try:
+		rc = RicciCommunicator(hostname)
+		if not rc:
+			raise Exception, 'None'
+	except Exception, e:
+		luci_log.debug_verbose('GSSL0: %s: %s' % (hostname, str(e)))
+		return []
+
+	service_list = list_services(rc)
+	if not service_list:
+		return []
+
+	svc_ret = list()
+	for i in service_list:
+		s = {}
+		try:
+			name = str(i.getAttribute('name'))
+		except:
+			name = None
+		s['name'] = name
+
+		try:
+			desc = i.getAttribute('description')
+		except:
+			desc = None
+		s['desc'] = desc
+
+		try:
+			enabled = i.getAttribute('enabled').lower()
+			if enabled == 'true':
+				s['enabled'] = True
+			else:
+				raise Exception, 'not enabled'
+		except:
+			s['enabled'] = False
+
+		try:
+			running = i.getAttribute('running').lower()
+			if running == 'true':
+				s['running'] = True
+				s['state'] = 'Running'
+			else:
+				raise Exception, 'not running'
+		except Exception, e:
+			s['running'] = False
+			s['state'] = 'Stopped'
+
+		s['starturl'] = '%s?pagetype=91&svcname=%s&systemname=%s&operation=start' % (request['URL'], s['name'], hostname)
+		s['stopurl'] = '%s?pagetype=91&svcname=%s&systemname=%s&operation=stop' % (request['URL'], s['name'], hostname)
+		s['restarturl'] = '%s?pagetype=91&svcname=%s&systemname=%s&operation=restart' % (request['URL'], s['name'], hostname)
+		svc_ret.append(s)
+
+	return svc_ret
+
+def validate_svc_update(self, request):
+	try:
+		form = request.form
+		hostname = form['systemname'].strip()
+		if not hostname:
+			raise Exception, 'blank'
+	except Exception, e:
+		return (False, {'errors': [ 'No system name was given.' ]})
+
+	try:
+		rc = RicciCommunicator(hostname)
+		if not rc:
+			raise Exception, 'unknown error'
+	except Exception, e:
+		luci_log.debug_verbose('VSU0: %s: %s' % (hostname, str(e)))
+		return (False, {'errors': [ 'Unable to connect to the ricci agent on %s: %s' % (hostname, str(e)) ]})
+
+	sys_svc_list = list()
+	sys_svc_hash = dict()
+
+	try:
+		for i in list_services(rc):
+			svc_name = str(i.getAttribute('name'))
+			sys_svc_hash[svc_name] = i
+			sys_svc_list.append(svc_name)
+	except Exception, e:
+		luci_log.debug_verbose('VSU1: %s: %s' % (hostname, str(e)))
+		return (False, {'errors': [ 'Unable to retrieve the list of services from %s' % hostname ]})
+
+	try:
+		del form['pagetype']
+		del form['systemname']
+	except:
+		pass
+
+	disable_list = filter(lambda x: not form.has_key(x) and sys_svc_hash[x].getAttribute('enabled').lower() == 'true', sys_svc_list)
+	enable_list = filter(lambda x: form.has_key(x) and sys_svc_hash[x].getAttribute('enabled').lower() != 'true', sys_svc_list)
+
+	updateServices(rc, enable_list, disable_list)
+	request.RESPONSE.redirect(request['URL'] + '?pagetype=90&systemname=' + hostname)
+
+def validate_manage_svc(self, request):
+	try:
+		hostname = request['systemname'].strip()
+	except:
+		return None
+
+	servicename = None
+	op = None
+	try:
+		servicename = request['svcname'].strip()
+		op = request['operation'].strip()
+	except:
+		pass
+
+	try:
+		rc = RicciCommunicator(hostname)
+		if not rc:
+			raise Exception, 'none'
+	except Exception, e:
+		return None
+
+	ret = None
+	try:
+		ret = svc_manage(rc, hostname, servicename, op)
+		luci_log.debug_verbose('VMC0: returning %s' % str(ret.toxml()))
+	except:
+		pass
+
+	return ret
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2007/02/22 20:52:51	1.243
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2007/02/23 22:07:45	1.244
@@ -41,6 +41,7 @@
 from GeneralError import GeneralError
 from homebase_adapters import manageCluster, createClusterSystems, havePermCreateCluster, setNodeFlag, delNodeFlag, userAuthenticated, getStorageNode, getClusterNode, delCluster, parseHostForm
 from LuciSyslog import LuciSyslog
+from system_adapters import validate_svc_update
 
 #Policy for showing the cluster chooser menu:
 #1) If there are no clusters in the ManagedClusterSystems
@@ -2453,7 +2454,8 @@
 	54: validateFenceEdit,
 	55: validateDaemonProperties,
 	57: deleteFenceDevice,
-	58: validateNodeFenceConfig
+	58: validateNodeFenceConfig,
+	90: validate_svc_update
 }
 
 def validatePost(self, request):
--- conga/luci/site/luci/Extensions/conga_constants.py	2007/02/01 20:49:08	1.36
+++ conga/luci/site/luci/Extensions/conga_constants.py	2007/02/23 22:07:45	1.37
@@ -48,6 +48,8 @@
 FENCEDEV_NODE_CONFIG = '58'
 
 CONF_EDITOR = '80'
+SYS_SERVICE_MANAGE = '90'
+SYS_SERVICE_UPDATE = '91'
 
 #Cluster tasks
 CLUSTER_STOP = '1000'
--- conga/luci/site/luci/Extensions/ricci_bridge.py	2007/02/22 20:52:51	1.58
+++ conga/luci/site/luci/Extensions/ricci_bridge.py	2007/02/23 22:07:45	1.59
@@ -486,6 +486,70 @@
 	ricci_xml = rc.batch_run(batch_str)
 	return batchAttemptResult(ricci_xml)
 
+def svc_manage(rc, hostname, servicename, op):
+	svc_func = None
+
+	doc = minidom.Document()
+	elem = doc.createElement('result')
+
+	if not servicename:
+		elem.setAttribute('service', 'No service name was specified.')
+		elem.setAttribute('message', 'No service name was specified.')
+		elem.setAttribute('success', '0')
+
+	if not op:
+		elem.setAttribute('operation', 'No operation was specified.')
+		elem.setAttribute('message', 'No operation was specified.')
+		elem.setAttribute('success', '0')
+
+	if not servicename or not op:
+		doc.appendChild(elem)
+		return doc
+
+	elem.setAttribute('service', servicename)
+	elem.setAttribute('operation', op)
+	elem.setAttribute('hostname', hostname)
+
+	try:
+		op = op.strip().lower()
+		if op == 'restart' or op == 'start' or op == 'stop':
+			svc_func = op
+		else:
+			raise Exception, op
+	except Exception, e:
+		elem.setAttribute('success', '0');
+		elem.setAttribute('message', 'Unknown operation')
+		doc.appendChild(elem)
+		return doc
+
+	batch_str = '<module name="service"><request API_version="1.0"><function_call name="%s"><var mutable="false" name="services" type="list_xml"><service name="%s"/></var></function_call></request></module>' % (svc_func, servicename)
+		
+	ricci_xml = rc.batch_run(batch_str, async=False)
+	if not ricci_xml or not ricci_xml.firstChild:
+		luci_log.debug_verbose('SVCM0: None returned')
+		elem.setAttribute('success', '0')
+		elem.setAttribute('message', 'operation failed')
+		doc.appendChild(elem)
+		return doc
+
+	elem.setAttribute('success', '0')
+	elem.setAttribute('message', str(ricci_xml.toxml()))
+	doc.appendChild(elem)
+	return doc
+
+def list_services(rc):
+	batch_str = '<module name="service"><request API_version="1.0"><function_call name="list"><var mutable="false" name="description" type="boolean" value="true"/></function_call></request></module>'
+	ricci_xml = rc.batch_run(batch_str, async=False)
+	if not ricci_xml or not ricci_xml.firstChild:
+		luci_log.debug_verbose('LS0: None returned')
+		return None
+	try:
+		service_tags = ricci_xml.getElementsByTagName('service')
+		return service_tags
+	except Exception, e:
+		luci_log.debug_verbose('LS1: %s' % str(e))
+	return None
+
 def nodeIsVirtual(rc):
 	batch_str = '<module name="cluster"><request API_version="1.0"><function_call name="virt_guest"/></request></module>'
 



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2007-09-25 22:47 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2007-09-25 22:47 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe at sourceware.org	2007-09-25 22:47:05

Modified files:
	luci/cluster   : form-chooser form-macros resource-form-macros 
	luci/homebase  : form-chooser form-macros luci_homebase.css 
	luci/plone-custom: sys_svc.css 
	luci/storage   : cylinder_select.js form-macros 
	                 storage_probing.js storage_utils.js 
	                 storage_validation.js validate_html 

Log message:
	More cleanup and fix some javascript bugs

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&r1=1.19&r2=1.20
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&r1=1.213&r2=1.214
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/resource-form-macros.diff?cvsroot=cluster&r1=1.42&r2=1.43
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/homebase/form-chooser.diff?cvsroot=cluster&r1=1.11&r2=1.12
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/homebase/form-macros.diff?cvsroot=cluster&r1=1.61&r2=1.62
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/homebase/luci_homebase.css.diff?cvsroot=cluster&r1=1.43&r2=1.44
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/sys_svc.css.diff?cvsroot=cluster&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/cylinder_select.js.diff?cvsroot=cluster&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/form-macros.diff?cvsroot=cluster&r1=1.28&r2=1.29
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/storage_probing.js.diff?cvsroot=cluster&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/storage_utils.js.diff?cvsroot=cluster&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/storage_validation.js.diff?cvsroot=cluster&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/validate_html.diff?cvsroot=cluster&r1=1.6&r2=1.7

--- conga/luci/cluster/form-chooser	2007/08/08 21:00:06	1.19
+++ conga/luci/cluster/form-chooser	2007/09/25 22:47:05	1.20
@@ -1,3 +1,12 @@
+<tal:comment tal:replace="nothing">
+** Copyright (C) 2006-2007 Red Hat, Inc.
+**
+** This program is free software; you can redistribute
+** it and/or modify it under the terms of version 2 of the
+** GNU General Public License as published by the
+** Free Software Foundation.
+</tal:comment>
+
 <html>
   <head>
     <title tal:content="string:"></title>
--- conga/luci/cluster/form-macros	2007/09/25 03:51:02	1.213
+++ conga/luci/cluster/form-macros	2007/09/25 22:47:05	1.214
@@ -1,3 +1,12 @@
+<tal:comment tal:replace="nothing">
+** Copyright (C) 2006-2007 Red Hat, Inc.
+**
+** This program is free software; you can redistribute
+** it and/or modify it under the terms of version 2 of the
+** GNU General Public License as published by the
+** Free Software Foundation.
+</tal:comment>
+
 <html>
 
 <head>
--- conga/luci/cluster/resource-form-macros	2007/09/25 03:51:02	1.42
+++ conga/luci/cluster/resource-form-macros	2007/09/25 22:47:05	1.43
@@ -1,3 +1,12 @@
+<tal:comment tal:replace="nothing">
+** Copyright (C) 2006-2007 Red Hat, Inc.
+**
+** This program is free software; you can redistribute
+** it and/or modify it under the terms of version 2 of the
+** GNU General Public License as published by the
+** Free Software Foundation.
+</tal:comment>
+
 <html>
 <head>
 	<title tal:content="template/title">The title</title>
--- conga/luci/homebase/form-chooser	2006/11/01 23:04:17	1.11
+++ conga/luci/homebase/form-chooser	2007/09/25 22:47:05	1.12
@@ -1,3 +1,12 @@
+<tal:comment tal:replace="nothing">
+** Copyright (C) 2006-2007 Red Hat, Inc.
+**
+** This program is free software; you can redistribute
+** it and/or modify it under the terms of version 2 of the
+** GNU General Public License as published by the
+** Free Software Foundation.
+</tal:comment>
+
 <html>
 
 <head>
--- conga/luci/homebase/form-macros	2007/09/25 03:51:21	1.61
+++ conga/luci/homebase/form-macros	2007/09/25 22:47:05	1.62
@@ -1,3 +1,12 @@
+<tal:comment tal:replace="nothing">
+** Copyright (C) 2006-2007 Red Hat, Inc.
+**
+** This program is free software; you can redistribute
+** it and/or modify it under the terms of version 2 of the
+** GNU General Public License as published by the
+** Free Software Foundation.
+</tal:comment>
+
 <html>
 
 <head>
--- conga/luci/homebase/luci_homebase.css	2007/09/25 03:51:21	1.43
+++ conga/luci/homebase/luci_homebase.css	2007/09/25 22:47:05	1.44
@@ -1,3 +1,12 @@
+/*
+** Copyright (C) 2006-2007 Red Hat, Inc.
+**
+** This program is free software; you can redistribute
+** it and/or modify it under the terms of version 2 of the
+** GNU General Public License as published by the
+** Free Software Foundation.
+*/
+
 input[type=text], input[type=password] {
 	padding: .2em ! important;
 	font-family: "Bitstream Vera Sans Mono", "DejaVu Sans Mono", monospace;
--- conga/luci/plone-custom/sys_svc.css	2007/06/28 16:02:50	1.1
+++ conga/luci/plone-custom/sys_svc.css	2007/09/25 22:47:05	1.2
@@ -1,3 +1,12 @@
+/*
+** Copyright (C) 2007 Red Hat, Inc.
+**
+** This program is free software; you can redistribute
+** it and/or modify it under the terms of version 2 of the
+** GNU General Public License as published by the
+** Free Software Foundation.
+*/
+
 input[type=image] {
 	border: 0;
 	background: transparent;
--- conga/luci/storage/cylinder_select.js	2007/09/25 18:55:13	1.3
+++ conga/luci/storage/cylinder_select.js	2007/09/25 22:47:05	1.4
@@ -58,12 +58,12 @@
 		}
 	}
 
-	parent = top.document.getElementById(properties_span_id);
+	var parent_elem = top.document.getElementById(properties_span_id);
 
-	for (var i = 0 ; i < parent.childNodes.length ; i++) {
-		var item = parent.childNodes[i];
+	for (var i = 0 ; i < parent_elem.childNodes.length ; i++) {
+		var item = parent_elem.childNodes[i];
 		var item_type = item.nodeName.toLowerCase();
-		if (item_type == 'span' || item.type == 'div') {
+		if (item_type == 'span' || item_type == 'div') {
 			if (item.id == current_selection) {
 				item.className = 'visible';
 			} else if (item.className == 'visible') {
@@ -86,7 +86,7 @@
 		var id = elem[0];
 		var beg = elem[1][0];
 		var end = elem[1][1];
-		if (x > beg && x < end) {
+		if (x >= beg && x <= end) {
 			select_subcyl(id, h_data);
 		}
 	}
--- conga/luci/storage/form-macros	2007/09/25 18:55:13	1.28
+++ conga/luci/storage/form-macros	2007/09/25 22:47:05	1.29
@@ -21,17 +21,18 @@
 
 <div metal:define-macro="commit-changes">
 	<script type="text/javascript" src="storage_utils.js"></script>
-	<span tal:omit-tag=""
-        tal:define="batch_id python:here.apply_storage_changes(ricci, storage_report, request);
-                    check_URL context/storage/check-batch/absolute_url;
-                    check_url python:check_URL + '?storagename=' + storagename + '&batch_id=' + batch_id">
+	<tal:block tal:define="
+		batch_id python:here.apply_storage_changes(ricci, storage_report, request);
+		check_URL context/storage/check-batch/absolute_url;
+		check_url python:check_URL + '?storagename=' + storagename + '&batch_id=' + batch_id">
 
 		<div metal:use-macro="here/form-macros/macros/display-committing-changes" />
+
 		<form id="urls_form">
 			<input type="hidden" name="check_url"
 				tal:attributes="value check_url" />
 		</form>
-	</span>
+	</tal:block>
 </div>
 
 <div metal:define-macro="display-committing-changes">
@@ -378,9 +379,9 @@
 </div>
 
 <div metal:define-macro="view-mapper-form">
-	<div metal:use-macro="here/form-macros/macros/content-scripts"/>
-	<div metal:use-macro="here/form-macros/macros/form-scripts"/>
-	<div metal:use-macro="here/form-macros/macros/single-visible-span"/>
+	<div metal:use-macro="here/form-macros/macros/content-scripts" />
+	<div metal:use-macro="here/form-macros/macros/form-scripts" />
+	<div metal:use-macro="here/form-macros/macros/single-visible-span" />
 
 	<tal:block tal:define="
 		mapper python:here.get_mapper_data(storage_report, request['mapper_id']);
@@ -401,7 +402,7 @@
 		<input type="checkbox" id="graphics_checkbox_id"
 			tal:attributes="
 				checked mapper/graphical_view"
-				onchange="var s = (this.checked)?'graphical_view':'textual_view'; singleVisibleSpan('mappings_view', s);" />
+				onchange="var s = (this.checked) ? 'graphical_view' : 'textual_view'; singleVisibleSpan('mappings_view', s);" />
 		Graphical View <small>(Uncheck if volumes are too small to select)</small>
 		<span id="mappings_view"
 			tal:define="
@@ -412,8 +413,9 @@
 				tal:define="global bd_path request/bd_path|nothing">
 
 				<tal:block tal:condition="not: bd_path">
-					<tal:block tal:define="global bd_path python:''"/>
+					<tal:block tal:define="global bd_path python:''" />
 				</tal:block>
+
 				<iframe style="border: none;"
 					tal:attributes="
 						src python:'mappings_provider?storagename=' + storagename + '&mapper_id=' + mapper['mapper_id'] + '&selected_path=' + bd_path;
@@ -545,138 +547,119 @@
 	<div metal:use-macro="here/form-macros/macros/form-scripts" />
 
 	<form method="get" tal:attributes="id mapper_template_form_id">
-    <input tal:attributes="type string:hidden;
-                           name string:pagetype;
-                           value string:commit_changes"/>
-
-    <input tal:attributes="type string:hidden;
-                           name string:object_type;
-                           value string:mapper_template"/>
 
-    <input tal:attributes="type string:hidden;
-                           name string:mapper_type;
-                           value mapper/mapper_type"/>
-
-    <input tal:attributes="type string:hidden;
-                           name string:mapper_id;
-                           value python:''"/>
+	<input type="hidden" name="pagetype"
+		tal:attributes="value string:commit_changes" />
 
-    <input tal:attributes="type string:hidden;
-                           name string:storagename;
-                           value storagename"/>
+	<input type="hidden" name="object_type" value="mapper_template" />
+	<input type="hidden" name="mapper_type"
+		tal:attributes="value mapper/mapper_type" />
+	<input type="hidden" name="mapper_id" value="" />
+
+	<input type="hidden" name="storagename"
+		tal:attributes="value storagename" />
+
+	<table class="props-form-table">
+		<tr class="props-form-header">
+			<th colspan="2" tal:attributes="
+				style python:here.add_commas('font-size: large', 'color: ' + mapper['color'])">
+				<table>
+					<tr>
+						<td style="min-width: 30px;">
+							<img tal:condition="mapper/icon"
+									tal:attributes="src mapper/icon"
+									height="29px"
+									width="29px" />
+						</td>
+						<td style="width: 100%;">
+							Creating New <span tal:replace="mapper/pretty_type" />
+						</td>
+						<td style="min-width: 30px;">&nbsp;</td>
+					</tr>
+				</table>
+			</th>
+		</tr>
+		<tr class="props-form-body">
+			<td>
+				<table class="props-inner-table"
+					tal:define="props mapper/props_ordered">
 
-    <table class="props-form-table">
-     <tr class="props-form-header">
-      <th colspan="2"
-          tal:attributes="style python:here.add_commas('font-size: large', 'color: ' + mapper['color'])">
-       <table>
-        <tr>
-         <td style="min-width: 30px;">
-          <img tal:condition="mapper/icon"
-               tal:attributes="src mapper/icon"
-               height="29px"
-               width="29px"/>
-         </td>
-         <td style="width: 100%;">
-          Creating New <span tal:replace="mapper/pretty_type"/>
-         </td>
-         <td style="min-width: 30px;">
-          &nbsp;
-         </td>
-        </tr>
-       </table>
-      </th>
-     </tr>
-     <tr class="props-form-body">
-      <td>
-       <table class="props-inner-table"
-              tal:define="props mapper/props_ordered">
-        <div metal:use-macro="here/form-macros/macros/display-props-tableless"/>
-       </table>
-      </td>
-      <td style="height: 100%;">
-       <table class="props-form-table"
-              style="height: 100%;">
-        <tr class="props-form-header">
-         <th>
-          <span tal:condition="python:mapper['min_sources'] == mapper['max_sources']">
-           Select <span tal:replace="mapper/min_sources"/> <span tal:replace="mapper/pretty_source_name"/>
-          </span>
-          <span tal:condition="python:mapper['min_sources'] != mapper['max_sources']">
-           Select <span tal:replace="mapper/min_sources"/> to <span tal:replace="mapper/max_sources"/> <span tal:replace="mapper/pretty_sources_name"/>
-          </span>
-         </th>
-        </tr>
-        <tr class="props-form-body">
-         <td>
-          <table class="props-inner-table">
-           <span tal:omit-tag=""
-                 tal:define="bds mapper/new_sources"
-                 tal:repeat="bd bds">
-            <tr>
-             <td>
-              <input tal:attributes="type string:checkbox;
-                                     name python:'source_bd_' + bd['path']"/>
-             </td>
-             <td tal:define="bytes bd/props/size/value;
-                             dummy python:here.bytes_to_value_units(bytes);
-                             size python:dummy[0];
-                             units python:dummy[1]">
-              <span tal:replace="bd/path"/> (<span tal:replace="size"/> <span tal:replace="units"/> - <span tal:replace="bd/pretty_type"/>)
-             </td>
-            </tr>
-           </span>
-           <tr>
-            <td colspan="2"
-                style="height: 100%;">
-             &nbsp;
-            </td>
-           </tr>
-          </table>
-         </td>
-        </tr>
-        <tr class="props-form-footer">
-         <td>
-          &nbsp;
-         </td>
-        </tr>
-       </table>
-      </td>
-     </tr>
-     <tr class="props-form-footer">
-      <td colspan="2">
-       <table style="width: 100%;">
-        <tr>
-         <td align="left">
-          &nbsp;
-         </td>
-         <td align="right">
-          <input type="button"
-                 name="action_type"
-                 value="Reset"
-                 onclick="return reset_form(this.form)"
-                 class="form_button"/>
-          <input tal:define="prompt_msg python:'Do you really want to create new ' + mapper['pretty_type'] + '?';
-                             validate_url context/validate_html/absolute_url"
-                 tal:attributes="id create_mapper_button_id;
-                                 type string:button;
-                                 name string:action_type;
-                                 value string:Create;
-                                 onclick python:'return validate_and_submit_form(\'' + validate_url + '\', \'' + mapper_template_form_id + '\', \'' + create_mapper_button_id + '\', \'' + prompt_msg + '\')'"
-                 class="form_button"/>
-         </td>
-        </tr>
-       </table>
-      </td>
-     </tr>
-    </table>
-   </form>
+					<div metal:use-macro="here/form-macros/macros/display-props-tableless" />
+				</table>
+			</td>
+			<td style="height: 100%;">
+				<table class="props-form-table" style="height: 100%;">
+					<tr class="props-form-header">
+						<th>
+							<span tal:condition="python:mapper['min_sources'] == mapper['max_sources']">
+								Select <span tal:replace="mapper/min_sources"/> <span tal:replace="mapper/pretty_source_name" />
+							</span>
+							<span tal:condition="python:mapper['min_sources'] != mapper['max_sources']">
+								Select <span tal:replace="mapper/min_sources" /> to <span tal:replace="mapper/max_sources" /> <span tal:replace="mapper/pretty_sources_name" />
+							</span>
+						</th>
+					</tr>
+					<tr class="props-form-body">
+						<td>
+							<table class="props-inner-table">
+								<tr tal:repeat="bd mapper/new_sources">
+									<td>
+										<input type="checkbox"
+											tal:attributes="name python:'source_bd_' + bd['path']" />
+									</td>
+									<td tal:define="
+											bytes bd/props/size/value;
+											dummy python:here.bytes_to_value_units(bytes);
+											size python:dummy[0];
+											units python:dummy[1]">
+										<span tal:replace="bd/path" /> (<span tal:replace="size" /> <span tal:replace="units" /> - <span tal:replace="bd/pretty_type" />)
+									</td>
+								</tr>
+								<tr>
+									<td colspan="2" style="height: 100%;">
+										&nbsp;
+									</td>
+								</tr>
+							</table>
+						</td>
+					</tr>
+					<tr class="props-form-footer">
+						<td>
+							&nbsp;
+						</td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+		<tr class="props-form-footer">
+			<td colspan="2">
+				<table style="width: 100%;">
+					<tr>
+						<td align="left">
+							&nbsp;
+						</td>
+						<td align="right">
+							<input type="button" name="action_type" value="Reset"
+								onclick="return reset_form(this.form)"
+								class="form_button" />
+
+							<input type="button" name="action_type"
+								value="Create" class="form_button"
+								tal:define="
+									prompt_msg python:'Do you really want to create new ' + mapper['pretty_type'] + '?';
+									validate_url context/validate_html/absolute_url"
+								tal:attributes="
+									id create_mapper_button_id;
+									onclick python:'return validate_and_submit_form(\'' + validate_url + '\', \'' + mapper_template_form_id + '\', \'' + create_mapper_button_id + '\', \'' + prompt_msg + '\')'" />
+						</td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+	</table>
+	</form>
 </div>
 
-
-
-
-
 <div metal:define-macro="add-sources-form" tal:define="
 	mapper python:here.get_mapper_data(storage_report, request['mapper_id']);
 	prefix python:'add_sources_to_' + mapper['mapper_id'] + '_';
@@ -688,249 +671,241 @@
 	<div metal:use-macro="here/form-macros/macros/forms-css" />
 	<div metal:use-macro="here/form-macros/macros/form-scripts" />
 
-   <span tal:omit-tag=""
-         tal:condition="not: mapper/new_sources">
-    There are no available <span tal:replace="mapper/pretty_sources_name"/> to be added to <span tal:replace="mapper/pretty_type"/> '<span tal:replace="mapper/pretty_name"/>'.
-     <br/>
-     <br/>
-    <a tal:define="go_to_mapper_url python:'./?pagetype=52&mapper_type=' + mapper['mapper_type'] + '&mapper_id=' + mapper['mapper_id'] + '&storagename=' + storagename"
-           tal:attributes="href go_to_mapper_url">
-     Go Back to <span tal:replace="mapper/pretty_type"/>
-    </a>
-   </span>
-   <form tal:condition="mapper/new_sources"
-         tal:attributes="id add_sources_form_id;
-                         method string:get">
-
-    <input tal:attributes="type string:hidden;
-                           name string:pagetype;
-                           value string:commit_changes"/>
+	<tal:block tal:condition="not: mapper/new_sources">
+		There are no available <span tal:replace="mapper/pretty_sources_name" /> to be added to <span tal:replace="mapper/pretty_type" /> '<span tal:replace="mapper/pretty_name" />'.
+		<br/>
+		<br/>
+		<a tal:define="
+				go_to_mapper_url python:'./?pagetype=52&mapper_type=' + mapper['mapper_type'] + '&mapper_id=' + mapper['mapper_id'] + '&storagename=' + storagename"
+			tal:attributes="href go_to_mapper_url">
+					Go Back to <span tal:replace="mapper/pretty_type" />
+		</a>
+	</tal:block>
 
-    <input tal:attributes="type string:hidden;
-                           name string:object_type;
-                           value string:add_sources"/>
+	<form method="get" tal:condition="mapper/new_sources"
+		tal:attributes="id add_sources_form_id">
 
-    <input tal:attributes="type string:hidden;
-                           name string:mapper_type;
-                           value mapper/mapper_type"/>
+	<input type="hidden" name="pagetype" value="commit_changes" />
+	<input type="hidden" name="object_type" value="add_sources" />
 
-    <input tal:attributes="type string:hidden;
-                           name string:mapper_id;
-                           value mapper/mapper_id"/>
+	<input type="hidden" name="mapper_type"
+		tal:attributes="value mapper/mapper_type"/>
 
-    <input tal:attributes="type string:hidden;
-                           name string:storagename;
-                           value storagename"/>
+	<input type="hidden" name="mapper_id"
+		tal:attributes="value mapper/mapper_id" />
+
+	<input type="hidden" name="storagename"
+		tal:attributes="value storagename" />
+
+	<table class="props-form-table">
+		<tr class="props-form-header">
+			<th colspan="2" tal:attributes="
+				style python:here.add_commas('font-size: large', 'color: ' + mapper['color'])">
+				<table>
+					<tr>
+						<td style="min-width: 30px;">
+							<img tal:condition="mapper/icon"
+								height="29px" width="29px"
+								tal:attributes="src mapper/icon" />
+						</td>
+						<td style="width: 100%;">
+							Adding new <span tal:replace="mapper/pretty_sources_name" /> to <span tal:replace="mapper/pretty_type" /> '<span tal:replace="mapper/pretty_name" />'
+						</td>
+						<td style="min-width: 30px;">
+							&nbsp;
+						</td>
+					</tr>
+				</table>
+			</th>
+		</tr>
 
-    <table class="props-form-table">
-     <tr class="props-form-header">
-      <th colspan="2"
-          tal:attributes="style python:here.add_commas('font-size: large', 'color: ' + mapper['color'])">
-       <table>
-        <tr>
-         <td style="min-width: 30px;">
-          <img tal:condition="mapper/icon"
-               tal:attributes="src mapper/icon"
-               height="29px"
-               width="29px"/>
-         </td>
-         <td style="width: 100%;">
-          Adding new <span tal:replace="mapper/pretty_sources_name"/> to <span tal:replace="mapper/pretty_type"/> '<span tal:replace="mapper/pretty_name"/>'
-         </td>
-         <td style="min-width: 30px;">
-          &nbsp;
-         </td>
-        </tr>
-       </table>
-      </th>
-     </tr>
-     <tr class="props-form-body">
-      <td style="height: 100%;">
-       <table class="props-inner-table">
-        <th colspan="2">
-         <span tal:condition="python:len(mapper['new_sources']) == 1">
-          Select <span tal:replace="mapper/pretty_source_name"/> to add
-         </span>
-         <span tal:condition="python:len(mapper['new_sources']) > 1">
-          Select one or more <span tal:replace="mapper/pretty_sources_name"/> to add
-         </span>
-        </th>
-        <span tal:omit-tag=""
-              tal:define="bds mapper/new_sources"
-              tal:repeat="bd bds">
-         <tr>
-          <td>
-           <input tal:attributes="type string:checkbox;
-                                  name python:'source_bd_' + bd['path']"/>
-          </td>
-          <td tal:define="bytes bd/props/size/value;
-                          dummy python:here.bytes_to_value_units(bytes);
-                          size python:dummy[0];
-                          units python:dummy[1]">
-           <span tal:replace="bd/path"/> (<span tal:replace="size"/> <span tal:replace="units"/> - <span tal:replace="bd/pretty_type"/>)
-          </td>
-         </tr>
-        </span>
-        <tr>
-         <td colspan="2"
-             style="height: 100%;">
-          &nbsp;
-         </td>
-        </tr>
-       </table>
-      </td>
-      <td>
-       &nbsp;
-      </td>
-     </tr>
-     <tr class="props-form-footer">
-      <td colspan="2">
-       <table style="width: 100%;">
-        <tr>
-         <td align="left">
-          &nbsp;
-         </td>
-         <td align="right">
-          <input tal:define="go_to_mapper_url python:'./?pagetype=52&mapper_type=' + mapper['mapper_type'] + '&mapper_id=' + mapper['mapper_id'] + '&storagename=' + storagename"
-                 tal:attributes="type string:button;
-                                 name string:cancel_button;
-                                 value string:Cancel;
-                                 onclick python:'window.location.assign(\'' + go_to_mapper_url + '\')'"
-                 class="form_button"/>
-          <input tal:define="prompt_msg python:'Do you really want to add selected ' + mapper['pretty_sources_name'] + ' to \\\'' + mapper['pretty_name'] + '\\\'?';
-                             validate_url context/validate_html/absolute_url"
-                 tal:attributes="id add_sources_button_id;
-                                 type string:button;
-                                 name string:action_type;
-                                 value string:Add;
-                                 onclick python:'return validate_and_submit_form(\'' + validate_url + '\', \'' + add_sources_form_id + '\', \'' + add_sources_button_id + '\', \'' + prompt_msg + '\')'"
-                 class="form_button"/>
-         </td>
-        </tr>
-       </table>
-      </td>
-     </tr>
-    </table>
-   </form>
+		<tr class="props-form-body">
+			<td style="height: 100%;">
+				<table class="props-inner-table">
+					<th colspan="2">
+						<span tal:condition="python:len(mapper['new_sources']) == 1">
+							Select <span tal:replace="mapper/pretty_source_name"/> to add
+						</span>
+						<span tal:condition="python:len(mapper['new_sources']) > 1">
+							Select one or more <span tal:replace="mapper/pretty_sources_name"/> to add
+						</span>
+					</th>
+					<tr tal:repeat="bd mapper/new_sources">
+						<td>
+							<input type="checkbox"
+								tal:attributes="name python:'source_bd_' + bd['path']" />
+						</td>
+						<td tal:define="
+							bytes bd/props/size/value;
+							dummy python:here.bytes_to_value_units(bytes);
+							size python:dummy[0];
+							units python:dummy[1]">
+
+							<span tal:replace="bd/path" /> (<span tal:replace="size" /> <span tal:replace="units" /> - <span tal:replace="bd/pretty_type" />)
+						</td>
+					</tr>
+					<tr>
+						<td colspan="2" style="height: 100%;">
+							&nbsp;
+						</td>
+					</tr>
+				</table>
+			</td>
+			<td>
+				&nbsp;
+			</td>
+		</tr>
+		<tr class="props-form-footer">
+			<td colspan="2">
+				<table style="width: 100%;">
+					<tr>
+						<td align="left">
+							&nbsp;
+						</td>
+						<td align="right">
+							<input type="button" name="cancel_button"
+								value="Cancel" class="form_button"
+								tal:define="
+									go_to_mapper_url python:'./?pagetype=52&mapper_type=' + mapper['mapper_type'] + '&mapper_id=' + mapper['mapper_id'] + '&storagename=' + storagename"
+								tal:attributes="
+									onclick python:'window.location.assign(\'' + go_to_mapper_url + '\')'" />
+
+							<input type="button" name="action_type"
+								value="Add" class="form_button"
+								tal:define="
+									prompt_msg python:'Do you really want to add selected ' + mapper['pretty_sources_name'] + ' to \\\'' + mapper['pretty_name'] + '\\\'?';
+									validate_url context/validate_html/absolute_url"
+								tal:attributes="
+									id add_sources_button_id;
+									onclick python:'return validate_and_submit_form(\'' + validate_url + '\', \'' + add_sources_form_id + '\', \'' + add_sources_button_id + '\', \'' + prompt_msg + '\')'" />
+						</td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+	</table>
+	</form>
 </div>
 
 <div tal:omit-tag="" metal:define-macro="display-props-tableless">
-   <span tal:omit-tag=""
-         tal:repeat="prop props">
-     <tr tal:define="p prop/name;
-                     prop_pr_name prop/pretty_name"
-         tal:condition="not: prop/hidden">
-      <td tal:content="prop_pr_name"/>
-      <td tal:define="prop_type prop/type;
-                      prop_units prop/units">
-       <table>
-        <tr>
-         <td>
-          <span tal:condition="python:prop_type == 'label'">
-           <span tal:omit-tag=""
-                 tal:condition="prop/replacements|nothing">
-            <input tal:attributes="type string:hidden;
-                                   name p;
-                                   value prop/value"/>
-            <select tal:define="repls prop/replacements;
-                                select_id python:prefix + '_select_replace_block_' + p"
-                    tal:attributes="id select_id;
-                                    onfocus python:'replace_properties_block__old_select_value = this.value';
-                                    onchange python:'replace_properties_block(\'' + properties_span_id + '\', \'' + select_id + '\')'">
-             <span tal:omit-tag=""
-                   tal:repeat="repl_name repls/repl_names">
-              <option tal:attributes="value python:repls[repl_name]['path']"/><span tal:replace="repl_name"/>
-             </span>
-            </select>
-           </span>
-           <span tal:omit-tag=""
-                 tal:condition="not: prop/replacements|nothing">
-            <span tal:condition="python: prop_units == 'bytes'">
-             <span tal:define="dummy python: here.bytes_to_value_units(prop['value']);
-                               value python: str(dummy[0]) + ' ' + str(dummy[1])"
-                   tal:replace="value"/>
-            </span>
-            <span tal:condition="python: prop_units != 'bytes'"
-                  tal:replace="prop/value"/>
-           </span>
-          </span>
-
-
-
-          <input tal:condition="python:prop_type == 'text'"
-                 tal:attributes="name p;
-                                 type string:text;
-                                 value prop/value;
-                                 onkeypress python:'return validate_text_keypress(this, event, 2, \'' + prop['validation']['illegal_chars'] + '\', ' + str(prop['validation']['max_length']) + ')';
-                                 onchange python:'validate_text(this, 2, \'' + prop['validation']['illegal_chars'] + '\', \'' + prop['validation']['reserved_words'] + '\', ' + str(prop['validation']['min_length']) + ', ' + str(prop['validation']['max_length']) + ', \'' + form_submit_button_id + '\')'"/>
-
-
+	<tal:block tal:repeat="prop props">
+		<tr tal:condition="not: prop/hidden"
+			tal:define="
+				p prop/name;
+				prop_pr_name prop/pretty_name">
+			<td tal:content="prop_pr_name" />
+			<td tal:define="
+				prop_type prop/type;
+				prop_units prop/units">
+				<table>
+					<tr>
+						<td>
+							<span tal:condition="python:prop_type == 'label'">
+								<tal:block tal:condition="prop/replacements|nothing">
+									<input type="hidden"
+										tal:attributes="
+											name p;
+											value prop/value" />
+									<select
+										tal:define="
+											repls prop/replacements;
+											select_id python:prefix + '_select_replace_block_' + p"
+										tal:attributes="
+											id select_id;
+											onfocus python:'replace_properties_block__old_select_value = this.value';
+											onchange python:'replace_properties_block(\'' + properties_span_id + '\', \'' + select_id + '\')'">
+										<tal:block tal:repeat="repl_name repls/repl_names">
+											<option tal:attributes="
+												value python:repls[repl_name]['path']" />
+											<span tal:replace="repl_name" />
+										</tal:block>
+									</select>
+								</tal:block>
+
+								<tal:block tal:condition="not: prop/replacements|nothing">
+									<span tal:condition="python: prop_units == 'bytes'">
+										<span tal:define="
+												dummy python: here.bytes_to_value_units(prop['value']);
+												value python: str(dummy[0]) + ' ' + str(dummy[1])"
+												tal:replace="value" />
+									</span>
+									<span tal:condition="python: prop_units != 'bytes'"
+										tal:replace="prop/value" />
+								</tal:block>
+							</span>
 
-          <span tal:omit-tag=""
-                tal:condition="python:prop_type == 'int' and prop_units != 'bytes'">
-           <input tal:attributes="name p;
-                                  type string:text;
-                                  size string:15;
-                                  value prop/value;
-                                  onchange python:'validate_int(this, 2, ' + str(prop['validation']['min']) + ', ' + str(prop['validation']['max']) + ', ' + str(prop['validation']['step']) + ', \'' + prop_units + '\', \'' + form_submit_button_id + '\')'"
-                  onkeypress="return validate_int_keypress(this, event, 2)"/>
-           (<span tal:replace="prop/validation/min"/> - <span tal:replace="prop/validation/max"/>)
-           <span tal:replace="prop_units"/>
-          </span>
-          <span tal:omit-tag=""
-                tal:condition="python:prop_type == 'int' and prop_units == 'bytes'">
-           <span tal:define="bytes prop/value;
-                             dummy python:here.bytes_to_value_prefunits(bytes);
-                             value python:dummy[0];
-                             units python:dummy[1];
-                             minim python:here.convert_bytes(prop['validation']['min'], units);
-                             maxim python:here.convert_bytes(prop['validation']['max'], units);
-                             step python:here.convert_bytes(prop['validation']['step'], units)">
-            <input tal:attributes="name p;
-                                   type string:text;
-                                   size string:15;
-                                   value value;
-                                   onchange python:'validate_float(this, 2, ' + str(minim) + ', ' + str(maxim) + ', ' + str(step) + ', \'' + units + '\', \'' + form_submit_button_id + '\')'"
-                   onkeypress="return validate_float_keypress(this, event, 2)"/>
-            (<span tal:replace="minim"/> - <span tal:replace="maxim"/>)
-            <span tal:replace="units"/>
-           </span>
-          </span>
+							<input type="text"
+								tal:condition="python:prop_type == 'text'"
+								tal:attributes="
+									name p;
+									value prop/value;
+									onkeypress python:'return validate_text_keypress(this, event, 2, \'' + prop['validation']['illegal_chars'] + '\', ' + str(prop['validation']['max_length']) + ')';
+									onchange python:'validate_text(this, 2, \'' + prop['validation']['illegal_chars'] + '\', \'' + prop['validation']['reserved_words'] + '\', ' + str(prop['validation']['min_length']) + ', ' + str(prop['validation']['max_length']) + ', \'' + form_submit_button_id + '\')'" />
+
+							<tal:block tal:condition="python:prop_type == 'int' and prop_units != 'bytes'">
+								<input type="text" size="15"
+									tal:attributes="
+										name p;
+										value prop/value;
+										onchange python:'validate_int(this, 2, ' + str(prop['validation']['min']) + ', ' + str(prop['validation']['max']) + ', ' + str(prop['validation']['step']) + ', \'' + prop_units + '\', \'' + form_submit_button_id + '\')'"
+									onkeypress="return validate_int_keypress(this, event, 2)" />
+								(<span tal:replace="prop/validation/min" /> - <span tal:replace="prop/validation/max" />) <span tal:replace="prop_units" />
+							</tal:block>
 
+							<tal:block tal:condition="python:prop_type == 'int' and prop_units == 'bytes'">
+								<span tal:define="
+									bytes prop/value;
+									dummy python:here.bytes_to_value_prefunits(bytes);
+									value python:dummy[0];
+									units python:dummy[1];
+									minim python:here.convert_bytes(prop['validation']['min'], units);
+									maxim python:here.convert_bytes(prop['validation']['max'], units);
+									step python:here.convert_bytes(prop['validation']['step'], units)">
 
+									<input type="string" size="15"
+										tal:attributes="
+											name p;
+											value value;
+											onchange python:'validate_float(this, 2, ' + str(minim) + ', ' + str(maxim) + ', ' + str(step) + ', \'' + units + '\', \'' + form_submit_button_id + '\')'"
+										onkeypress="return validate_float_keypress(this, event, 2)" />
+									(<span tal:replace="minim" /> - <span tal:replace="maxim" />) <span tal:replace="units" />
+								</span>
+							</tal:block>
 
-          <span tal:condition="python:prop_type == 'select'">
-           <select tal:define="prop_options prop/value"
-                   tal:attributes="name p">
-            <span tal:omit-tag=""
-                  tal:condition="python: prop_units != 'bytes'"
-                  tal:repeat="prop_opt prop_options">
-             <option tal:attributes="value prop_opt"/><span tal:replace="prop_opt"/>
-            </span>
-            <span tal:omit-tag=""
-                  tal:condition="python: prop_units == 'bytes'"
-                  tal:repeat="prop_opt prop_options">
-             <option tal:attributes="value prop_opt"/><span tal:define="dummy python: here.bytes_to_value_units(prop_opt);
-                                                                        value python: str(dummy[0]) + ' ' + str(dummy[1])"
-                                                            tal:replace="value"/>
-            </span>
-           </select>
-          </span>
-         </td>
-         <td>
-          <span tal:condition="python: prop_units != 'bytes'"
-                tal:replace="prop_units"/>
-         </td>
-        </tr>
-       </table>
-      </td>
-     </tr>
-   </span>
-   <tr>
-    <td colspan="2" style="height: 100%;">
-     &nbsp;
-    </td>
-   </tr>
+							<tal:block tal:condition="python:prop_type == 'select'">
+								<select tal:define="prop_options prop/value" tal:attributes="name p">
+									<tal:block
+										tal:condition="python: prop_units != 'bytes'"
+										tal:repeat="prop_opt prop_options">
+										<option tal:attributes="value prop_opt" />
+										<span tal:replace="prop_opt" />
+									</tal:block>
+									<tal:block
+										tal:condition="python: prop_units == 'bytes'"
+										tal:repeat="prop_opt prop_options">
+										<option tal:attributes="value prop_opt" />
+										<span
+											tal:define="
+												dummy python: here.bytes_to_value_units(prop_opt);
+												value python: str(dummy[0]) + ' ' + str(dummy[1])"
+											tal:replace="value" />
+									</tal:block>
+								</select>
+							</tal:block>
+						</td>
+						<td>
+							<span tal:condition="python: prop_units != 'bytes'" tal:replace="prop_units" />
+						</td>
+					</tr>
+				</table>
+			</td>
+		</tr>
+	</tal:block>
+	<tr>
+		<td colspan="2" style="height: 100%;">
+			&nbsp;
+		</td>
+	</tr>
 </div>
 
 <div tal:omit-tag="" metal:define-macro="display-props">
@@ -968,7 +943,7 @@
 <div metal:define-macro="display-BD">
 	<div metal:use-macro="here/form-macros/macros/forms-css" />
 
-   <span tal:omit-tag=""
+	<span tal:omit-tag=""
          tal:define="mapper string:;
                      conts python:bd_data['contents'];
                      prefix prefix|bd_data/path;
@@ -978,9 +953,8 @@
                      apply_button_id python:prefix + 'apply_button_id';
                      form_submit_button_id apply_button_id;
                      content_span_id python:prefix + 'content_span_id'">
-    <form tal:attributes="id bd_form_id;
-                          method string:get">
 
+    <form method="get" tal:attributes="id bd_form_id">
      <input tal:attributes="type string:hidden;
                             name string:pagetype;
                             value string:commit_changes"/>
@@ -1089,11 +1063,11 @@
                       tal:attributes="id select_content_id;
                                       name string:content_id;
                                       onchange funct">
-               <span tal:omit-tag=""
-                     tal:repeat="cont conts">
+               <span tal:omit-tag="" tal:repeat="cont conts">
                 <option tal:attributes="value cont/id"/><span tal:replace="cont/name"/>
                </span>
               </select>
+
               <span tal:define="cont python:conts[0]"
                     tal:condition="python:len(conts) == 1">
                <input tal:attributes="id select_content_id;
@@ -1338,8 +1312,10 @@
                   value="Reset"
                   onclick="return reset_form(this.form)"
                   class="form_button"/>
-           <input tal:define="prompt_msg python:'Do you really want to apply changes to ' + mapper['pretty_type'] + ' \\\'' + mapper['pretty_name'] + '\\\'?';
-                              validate_url context/validate_html/absolute_url"
+
+           <input tal:define="
+					prompt_msg python:'Do you really want to apply changes to ' + mapper['pretty_type'] + ' \\\'' + mapper['pretty_name'] + '\\\'?';
+					validate_url context/validate_html/absolute_url"
                   tal:attributes="id apply_button_id;
                                   type string:button;
                                   name string:action_type;
--- conga/luci/storage/storage_probing.js	2007/09/25 16:49:36	1.1
+++ conga/luci/storage/storage_probing.js	2007/09/25 22:47:05	1.2
@@ -9,7 +9,9 @@
 
 function strip_left(txt) {
 	for (var i = 0 ; i < txt.length ; i++) {
-		if (txt[i] == " " || txt[i] == "\n") {
+		if (txt[i] == ' ' || txt[i] == '\n' ||
+			txt[i] == '\r' || txt[i] == '\t')
+		{
 			continue;
 		}
 		return txt.substr(i);
--- conga/luci/storage/storage_utils.js	2007/09/25 16:49:36	1.1
+++ conga/luci/storage/storage_utils.js	2007/09/25 22:47:05	1.2
@@ -9,7 +9,9 @@
 
 function strip_left(txt) {
 	for (var i = 0 ; i < txt.length ; i++) {
-		if (txt[i] == " " || txt[i] == "\n") {
+		if (txt[i] == ' ' || txt[i] == '\n' ||
+			txt[i] == '\r' || txt[i] == '\t')
+		{
 			continue;
 		}
 		return txt.substr(i);
--- conga/luci/storage/storage_validation.js	2007/09/25 16:49:36	1.1
+++ conga/luci/storage/storage_validation.js	2007/09/25 22:47:05	1.2
@@ -305,7 +305,9 @@
 
 function strip_left(txt) {
 	for (var i = 0 ; i < txt.length ; i++) {
-		if (txt[i] == " " || txt[i] == "\n") {
+		if (txt[i] == ' ' || txt[i] == '\n' ||
+			txt[i] == '\r' || txt[i] == '\t')
+		{
 			continue;
 		}
 		return txt.substr(i);
@@ -346,7 +348,7 @@
 					}
 				}
 
-				alert(err_msg);
+				alert(err_msg || 'An unknown error occurred');
 			}
 		} else {
 			alert("Error retrieving data from server");
--- conga/luci/storage/validate_html	2007/09/25 18:55:13	1.6
+++ conga/luci/storage/validate_html	2007/09/25 22:47:05	1.7
@@ -31,7 +31,7 @@
 
 <tal:block tal:condition="access_to_host_allowed">
 	<span tal:condition="python:action_type == 'Validate'"
-		tal:content="python:here.validate(storage_report, request)" />
+		tal:replace="python:here.validate(storage_report, request)" />
 
 	<tal:block tal:condition="python:action_type != 'Validate'">
 		This form is to be used for validation only



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2007-03-12  4:25 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2007-03-12  4:25 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe at sourceware.org	2007-03-12 04:25:41

Modified files:
	luci/cluster   : form-chooser form-macros 
	luci/site/luci/Extensions: cluster_adapters.py 
	                           conga_constants.py ricci_bridge.py 

Log message:
	Frontend support for virtual service live migration

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&r1=1.17&r2=1.18
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&r1=1.196&r2=1.197
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.247&r2=1.248
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&r1=1.37&r2=1.38
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/ricci_bridge.py.diff?cvsroot=cluster&r1=1.60&r2=1.61

--- conga/luci/cluster/form-chooser	2007/02/23 22:07:45	1.17
+++ conga/luci/cluster/form-chooser	2007/03/12 04:25:41	1.18
@@ -92,6 +92,9 @@
     <span tal:omit-tag="" tal:condition="python: ptype == '28'">
      <div metal:use-macro="here/form-macros/macros/servicerestart"/>
     </span>
+    <span tal:omit-tag="" tal:condition="python: ptype == '59'">
+     <div metal:use-macro="here/form-macros/macros/servicemigrate"/>
+    </span>
     <span tal:omit-tag="" tal:condition="python: ptype == '30'">
      <div metal:use-macro="here/resource-form-macros/macros/resources-form"/>
     </span>
--- conga/luci/cluster/form-macros	2007/03/05 16:50:43	1.196
+++ conga/luci/cluster/form-macros	2007/03/12 04:25:41	1.197
@@ -3876,12 +3876,12 @@
 
 			<tr class="cluster service info_top">
 				<td class="cluster service service_name">
-					<strong class="cluster service">Service Name:</strong>
+					<strong class="cluster service">Service Name</strong>
 					<a tal:attributes="
 						href svc/cfgurl;
 						class python: 'cluster service ' + (running and 'running' or 'stopped')"
 						tal:content="svc/name" />
-					<tal:block tal:condition="exists:svc/virt">
+					<tal:block tal:condition="exists:svc/is_vm">
 						(virtual service)
 					</tal:block>
 				</td>
@@ -3898,7 +3898,7 @@
 
 							<option
 								tal:condition="running"
-								tal:attributes="value svc/retstarturl| nothing"
+								tal:attributes="value svc/restarturl | nothing"
 								tal:content="string:Restart this service" />
 
 							<option
@@ -3909,14 +3909,40 @@
 							<option
 								tal:condition="not: running"
 								tal:attributes="value svc/enableurl | nothing"
-								tal:content="string:Start this service" />
+								tal:content="string:Enable this service" />
 
 							<option
 								tal:condition="not: running"
 								tal:attributes="value svc/delurl | nothing"
 								tal:content="string:Delete this service" />
+
 							<option value="">----------</option>
-							<option tal:repeat="starturl svc/links" tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename"/></option>
+
+							<tal:block tal:condition="not: running">
+								<tal:block tal:repeat="starturl svc/links">
+									<option
+										tal:condition="not:exists: starturl/migrate"
+										tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+							</tal:block>
+
+							<tal:block tal:condition="running">
+								<tal:block tal:repeat="starturl svc/links">
+									<option
+										tal:condition="not:exists: starturl/migrate"
+										tal:attributes="value starturl/url">Relocate this service to <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+
+								<tal:block tal:condition="svc/is_vm | nothing">
+									<option value="">----------</option>
+									<tal:block tal:repeat="starturl svc/links">
+										<option
+											tal:condition="exists: starturl/migrate"
+											tal:attributes="value starturl/url">Migrate this service to <span tal:replace="starturl/nodename" /></option>
+									</tal:block>
+								</tal:block>
+							</tal:block>
+
 						</select>
 						<input type="button" value="Go"
 							onclick="if (this.form.gourl[this.form.gourl.selectedIndex].value && confirm(this.form.gourl[this.form.gourl.selectedIndex].text + '?')) return dropdown(this.form.gourl)" />
@@ -4227,10 +4253,19 @@
 
 	<tal:block tal:define="
 		result python: here.serviceStart(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
+<div metal:define-macro="servicemigrate">
+	<script type="text/javascript">
+		set_page_title('Luci ??? cluster ??? services ??? Migrate a virtual service');
+	</script>
+
+	<tal:block tal:define="
+		global ricci_agent ri_agent | python: here.getRicciAgentForCluster(request)" />
+
+	<tal:block tal:define="
+		result python: here.serviceMigrate(ricci_agent, request)" />
+</div>
 
 <div metal:define-macro="servicerestart">
 	<script type="text/javascript">
@@ -4242,8 +4277,6 @@
 
 	<tal:block tal:define="
 		result python: here.serviceRestart(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
 <div metal:define-macro="servicestop">
@@ -4256,8 +4289,6 @@
 
 	<span tal:define="
 		result python: here.serviceStop(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
 <div metal:define-macro="serviceconfig-type-macro" tal:omit-tag="">
@@ -4367,22 +4398,51 @@
 
 						<option value="">Choose a Task...</option>
 						<tal:block tal:condition="running">
+							<option
+								tal:attributes="value innermap/restarturl">Restart this service</option>
+
+							<option
+								tal:attributes="value innermap/disableurl">Disable this service</option>
+
 							<option value="">----------</option>
-							<option value="" tal:attributes="value innermap/restarturl">Restart this service</option>
-							<option value="" tal:attributes="value innermap/disableurl">Disable this service</option>
-							<option value="">----------</option>
-							<option tal:repeat="starturl innermap/links" value="" tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename"/></option>
+
+							<tal:block tal:repeat="starturl innermap/links">
+								<option
+									tal:condition="not:exists: starturl/migrate"
+									tal:attributes="value starturl/url">Relocate this service to <span tal:replace="starturl/nodename" />
+								</option>
+							</tal:block>
+
+							<tal:block tal:condition="svc/is_vm | nothing">
+								<option value="">----------</option>
+								<tal:block tal:repeat="starturl innermap/links">
+									<option
+										tal:condition="exists: starturl/migrate"
+										tal:attributes="value starturl/url">Migrate this service to <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+							</tal:block>
 						</tal:block>
 
 						<tal:block tal:condition="not: running">
+							<option
+								tal:attributes="value innermap/enableurl">Enable this service</option>
 							<option value="">----------</option>
-							<option value="" tal:attributes="value innermap/enableurl">Enable this service</option>
+
+							<tal:block tal:repeat="starturl innermap/links">
+								<option
+									tal:condition="not:exists: starturl/migrate"
+									tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename" />
+								</option>
+							</tal:block>
+
 							<option value="">----------</option>
+
 							<option
 								tal:attributes="value innermap/delurl | nothing"
 								tal:content="string:Delete this service" />
 						</tal:block>
 					</select>
+
 					<input type="button" value="Go"
 						onclick="if (this.form.gourl[this.form.gourl.selectedIndex].value && confirm(this.form.gourl[this.form.gourl.selectedIndex].text + '?')) return dropdown(this.form.gourl)" />
 				</form>
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2007/03/06 22:48:19	1.247
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2007/03/12 04:25:41	1.248
@@ -3441,15 +3441,6 @@
 
 			itemmap['autostart'] = item['autostart']
 
-			starturls = list()
-			for node in nodes:
-				starturl = {}
-				if node.getName() != cur_node:
-					starturl['nodename'] = node.getName()
-					starturl['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_START + '&nodename=' + node.getName()
-					starturls.append(starturl)
-			itemmap['links'] = starturls
-
 			try:
 				svc = model.retrieveServiceByName(item['name'])
 				itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + SERVICE
@@ -3457,11 +3448,29 @@
 			except:
 				try:
 					svc = model.retrieveVMsByName(item['name'])
-					itemmap['virt'] = True
+					itemmap['is_vm'] = True
 					itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + VM_CONFIG 
 					itemmap['delurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + VM_CONFIG
 				except:
 					continue
+
+			starturls = list()
+			for node in nodes:
+				if node.getName() != cur_node:
+					starturl = {}
+					cur_nodename = node.getName()
+					starturl['nodename'] = cur_nodename
+					starturl['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_START + '&nodename=' + node.getName()
+					starturls.append(starturl)
+
+					if itemmap.has_key('is_vm') and itemmap['is_vm'] is True:
+						migrate_url = { 'nodename': cur_nodename }
+						migrate_url['migrate'] = True
+						migrate_url['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_MIGRATE + '&nodename=' + node.getName()
+						starturls.append(migrate_url)
+
+			itemmap['links'] = starturls
+
 			dom = svc.getAttribute("domain")
 			if dom is not None:
 				itemmap['faildom'] = dom
@@ -3515,42 +3524,59 @@
 		return hmap
 
 	for item in status:
-		if item['type'] == "service":
+		innermap = {}
+		if item['type'] == 'service':
 			if item['name'] == servicename:
 				hmap['name'] = servicename
-				starturls = list()
 				hmap['autostart'] = item['autostart']
-				if item['running'] == "true":
-					hmap['running'] = "true"
-					#In this case, determine where it can run...
-					innermap = {}
+
+				starturls = list()
+				if item['running'] == 'true':
+					hmap['running'] = 'true'
 					nodename = item['nodename']
-					innermap['current'] = "This service is currently running on %s" % nodename
+					innermap['current'] = 'This service is currently running on %s' % nodename
+
 					innermap['disableurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_STOP
 					innermap['restarturl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_RESTART
 					innermap['delurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_DELETE
 
+					#In this case, determine where it can run...
 					nodes = model.getNodes()
 					for node in nodes:
-						starturl = {}
 						if node.getName() != nodename:
-							starturl['nodename'] = node.getName()
+							starturl = {}
+							cur_nodename = node.getName()
+							starturl['nodename'] = cur_nodename
 							starturl['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START + "&nodename=" + node.getName()
 							starturls.append(starturl)
+
+							if item.has_key('is_vm') and item['is_vm'] is True:
+								migrate_url = { 'nodename': cur_nodename }
+								migrate_url['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_MIGRATE + "&nodename=" + node.getName()
+								migrate_url['migrate'] = True
+								starturls.append(migrate_url)
 					innermap['links'] = starturls
 				else:
 					#Do not set ['running'] in this case...ZPT will detect it is missing
-					#In this case, determine where it can run...
-					innermap = {}
 					innermap['current'] = "This service is currently stopped"
 					innermap['enableurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START
+					innermap['delurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_DELETE
+
 					nodes = model.getNodes()
 					starturls = list()
 					for node in nodes:
 						starturl = {}
-						starturl['nodename'] = node.getName()
+						cur_nodename = node.getName()
+
+						starturl['nodename'] = cur_nodename
 						starturl['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START + "&nodename=" + node.getName()
 						starturls.append(starturl)
+
+						if item.has_key('is_vm') and item['is_vm'] is True:
+							migrate_url = { 'nodename': cur_nodename }
+							migrate_url['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_MIGRATE + "&nodename=" + node.getName()
+							migrate_url['migrate'] = True
+							starturls.append(migrate_url)
 					innermap['links'] = starturls
 				hmap['innermap'] = innermap
 
@@ -3661,14 +3687,72 @@
 
 	batch_number, result = startService(rc, svcname, nodename)
 	if batch_number is None or result is None:
-		luci_log.debug_verbose('startService3: SS(%s,%s,%s) call failed' \
+		luci_log.debug_verbose('serviceStart3: SS(%s,%s,%s) call failed' \
+			% (svcname, cluname, nodename))
+		return None
+
+	try:
+		status_msg = "Starting service \'%s\'" % svcname
+		if nodename:
+			status_msg += " on node \'%s\'" % nodename
+		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, status_msg)
+	except Exception, e:
+		luci_log.debug_verbose('serviceStart4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
+
+	response = req.RESPONSE
+	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
+
+def serviceMigrate(self, rc, req):
+	svcname = None
+	try:
+		svcname = req['servicename']
+	except:
+		try:
+			svcname = req.form['servicename']
+		except:
+			pass
+
+	if svcname is None:
+		luci_log.debug_verbose('serviceMigrate0: no service name')
+		return None
+
+	nodename = None
+	try:
+		nodename = req['nodename']
+	except:
+		try:
+			nodename = req.form['nodename']
+		except:
+			pass
+
+	if nodename is None:
+		luci_log.debug_verbose('serviceMigrate1: no target node name')
+		return None
+		
+	cluname = None
+	try:
+		cluname = req['clustername']
+	except KeyError, e:
+		try:
+			cluname = req.form['clustername']
+		except:
+			pass
+
+	if cluname is None:
+		luci_log.debug_verbose('serviceMigrate2: no cluster name for svc %s' \
+			% svcname)
+		return None
+
+	batch_number, result = migrateService(rc, svcname, nodename)
+	if batch_number is None or result is None:
+		luci_log.debug_verbose('serviceMigrate3: SS(%s,%s,%s) call failed' \
 			% (svcname, cluname, nodename))
 		return None
 
 	try:
-		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, "Starting service \'%s\'" % svcname)
+		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, "Migrating service \'%s\' to node \'%s\'" % (svcname, nodename))
 	except Exception, e:
-		luci_log.debug_verbose('startService4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
+		luci_log.debug_verbose('serviceMigrate4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
 
 	response = req.RESPONSE
 	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
--- conga/luci/site/luci/Extensions/conga_constants.py	2007/02/23 22:07:45	1.37
+++ conga/luci/site/luci/Extensions/conga_constants.py	2007/03/12 04:25:41	1.38
@@ -44,8 +44,9 @@
 FENCEDEV="54"
 CLUSTER_DAEMON="55"
 SERVICE_DELETE = '56'
-FENCEDEV_DELETE = "57"
+FENCEDEV_DELETE = '57'
 FENCEDEV_NODE_CONFIG = '58'
+SERVICE_MIGRATE = '59'
 
 CONF_EDITOR = '80'
 SYS_SERVICE_MANAGE = '90'
--- conga/luci/site/luci/Extensions/ricci_bridge.py	2007/02/24 07:02:42	1.60
+++ conga/luci/site/luci/Extensions/ricci_bridge.py	2007/03/12 04:25:41	1.61
@@ -454,6 +454,12 @@
 	ricci_xml = rc.batch_run(batch_str)
 	return batchAttemptResult(ricci_xml)
 
+def migrateService(rc, servicename, preferrednode):
+	batch_str = '<module name="cluster"><request API_version="1.0"><function_call name="migrate_service"><var mutable="false" name="servicename" type="string" value=\"' + servicename + '\"/><var mutable="false" name="nodename" type="string" value=\"' + preferrednode + '\" /></function_call></request></module>'
+
+	ricci_xml = rc.batch_run(batch_str)
+	return batchAttemptResult(ricci_xml)
+
 def updateServices(rc, enable_list, disable_list):
 	batch = ''
 



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2007-03-12  4:24 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2007-03-12  4:24 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Branch: 	RHEL4
Changes by:	rmccabe at sourceware.org	2007-03-12 04:24:34

Modified files:
	luci/cluster   : form-chooser form-macros 
	luci/site/luci/Extensions: cluster_adapters.py 
	                           conga_constants.py ricci_bridge.py 

Log message:
	Frontend support for virtual service live migration

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=1.16&r2=1.16.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=1.176.2.15&r2=1.176.2.16
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=1.227.2.13&r2=1.227.2.14
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=1.36.2.1&r2=1.36.2.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/ricci_bridge.py.diff?cvsroot=cluster&only_with_tag=RHEL4&r1=1.56.2.4&r2=1.56.2.5

--- conga/luci/cluster/form-chooser	2007/02/01 20:27:33	1.16
+++ conga/luci/cluster/form-chooser	2007/03/12 04:24:33	1.16.2.1
@@ -92,6 +92,9 @@
     <span tal:omit-tag="" tal:condition="python: ptype == '28'">
      <div metal:use-macro="here/form-macros/macros/servicerestart"/>
     </span>
+    <span tal:omit-tag="" tal:condition="python: ptype == '59'">
+     <div metal:use-macro="here/form-macros/macros/servicemigrate"/>
+    </span>
     <span tal:omit-tag="" tal:condition="python: ptype == '30'">
      <div metal:use-macro="here/resource-form-macros/macros/resources-form"/>
     </span>
--- conga/luci/cluster/form-macros	2007/03/05 16:49:42	1.176.2.15
+++ conga/luci/cluster/form-macros	2007/03/12 04:24:33	1.176.2.16
@@ -3876,12 +3876,12 @@
 
 			<tr class="cluster service info_top">
 				<td class="cluster service service_name">
-					<strong class="cluster service">Service Name:</strong>
+					<strong class="cluster service">Service Name</strong>
 					<a tal:attributes="
 						href svc/cfgurl;
 						class python: 'cluster service ' + (running and 'running' or 'stopped')"
 						tal:content="svc/name" />
-					<tal:block tal:condition="exists:svc/virt">
+					<tal:block tal:condition="exists:svc/is_vm">
 						(virtual service)
 					</tal:block>
 				</td>
@@ -3898,7 +3898,7 @@
 
 							<option
 								tal:condition="running"
-								tal:attributes="value svc/retstarturl| nothing"
+								tal:attributes="value svc/restarturl | nothing"
 								tal:content="string:Restart this service" />
 
 							<option
@@ -3909,14 +3909,40 @@
 							<option
 								tal:condition="not: running"
 								tal:attributes="value svc/enableurl | nothing"
-								tal:content="string:Start this service" />
+								tal:content="string:Enable this service" />
 
 							<option
 								tal:condition="not: running"
 								tal:attributes="value svc/delurl | nothing"
 								tal:content="string:Delete this service" />
+
 							<option value="">----------</option>
-							<option tal:repeat="starturl svc/links" tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename"/></option>
+
+							<tal:block tal:condition="not: running">
+								<tal:block tal:repeat="starturl svc/links">
+									<option
+										tal:condition="not:exists: starturl/migrate"
+										tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+							</tal:block>
+
+							<tal:block tal:condition="running">
+								<tal:block tal:repeat="starturl svc/links">
+									<option
+										tal:condition="not:exists: starturl/migrate"
+										tal:attributes="value starturl/url">Relocate this service to <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+
+								<tal:block tal:condition="svc/is_vm | nothing">
+									<option value="">----------</option>
+									<tal:block tal:repeat="starturl svc/links">
+										<option
+											tal:condition="exists: starturl/migrate"
+											tal:attributes="value starturl/url">Migrate this service to <span tal:replace="starturl/nodename" /></option>
+									</tal:block>
+								</tal:block>
+							</tal:block>
+
 						</select>
 						<input type="button" value="Go"
 							onclick="if (this.form.gourl[this.form.gourl.selectedIndex].value && confirm(this.form.gourl[this.form.gourl.selectedIndex].text + '?')) return dropdown(this.form.gourl)" />
@@ -4227,10 +4253,19 @@
 
 	<tal:block tal:define="
 		result python: here.serviceStart(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
+<div metal:define-macro="servicemigrate">
+	<script type="text/javascript">
+		set_page_title('Luci ??? cluster ??? services ??? Migrate a virtual service');
+	</script>
+
+	<tal:block tal:define="
+		global ricci_agent ri_agent | python: here.getRicciAgentForCluster(request)" />
+
+	<tal:block tal:define="
+		result python: here.serviceMigrate(ricci_agent, request)" />
+</div>
 
 <div metal:define-macro="servicerestart">
 	<script type="text/javascript">
@@ -4242,8 +4277,6 @@
 
 	<tal:block tal:define="
 		result python: here.serviceRestart(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
 <div metal:define-macro="servicestop">
@@ -4256,8 +4289,6 @@
 
 	<span tal:define="
 		result python: here.serviceStop(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
 <div metal:define-macro="serviceconfig-type-macro" tal:omit-tag="">
@@ -4367,22 +4398,51 @@
 
 						<option value="">Choose a Task...</option>
 						<tal:block tal:condition="running">
+							<option
+								tal:attributes="value innermap/restarturl">Restart this service</option>
+
+							<option
+								tal:attributes="value innermap/disableurl">Disable this service</option>
+
 							<option value="">----------</option>
-							<option value="" tal:attributes="value innermap/restarturl">Restart this service</option>
-							<option value="" tal:attributes="value innermap/disableurl">Disable this service</option>
-							<option value="">----------</option>
-							<option tal:repeat="starturl innermap/links" value="" tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename"/></option>
+
+							<tal:block tal:repeat="starturl innermap/links">
+								<option
+									tal:condition="not:exists: starturl/migrate"
+									tal:attributes="value starturl/url">Relocate this service to <span tal:replace="starturl/nodename" />
+								</option>
+							</tal:block>
+
+							<tal:block tal:condition="svc/is_vm | nothing">
+								<option value="">----------</option>
+								<tal:block tal:repeat="starturl innermap/links">
+									<option
+										tal:condition="exists: starturl/migrate"
+										tal:attributes="value starturl/url">Migrate this service to <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+							</tal:block>
 						</tal:block>
 
 						<tal:block tal:condition="not: running">
+							<option
+								tal:attributes="value innermap/enableurl">Enable this service</option>
 							<option value="">----------</option>
-							<option value="" tal:attributes="value innermap/enableurl">Enable this service</option>
+
+							<tal:block tal:repeat="starturl innermap/links">
+								<option
+									tal:condition="not:exists: starturl/migrate"
+									tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename" />
+								</option>
+							</tal:block>
+
 							<option value="">----------</option>
+
 							<option
 								tal:attributes="value innermap/delurl | nothing"
 								tal:content="string:Delete this service" />
 						</tal:block>
 					</select>
+
 					<input type="button" value="Go"
 						onclick="if (this.form.gourl[this.form.gourl.selectedIndex].value && confirm(this.form.gourl[this.form.gourl.selectedIndex].text + '?')) return dropdown(this.form.gourl)" />
 				</form>
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2007/03/05 16:49:42	1.227.2.13
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2007/03/12 04:24:34	1.227.2.14
@@ -3439,15 +3439,6 @@
 
 			itemmap['autostart'] = item['autostart']
 
-			starturls = list()
-			for node in nodes:
-				starturl = {}
-				if node.getName() != cur_node:
-					starturl['nodename'] = node.getName()
-					starturl['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_START + '&nodename=' + node.getName()
-					starturls.append(starturl)
-			itemmap['links'] = starturls
-
 			try:
 				svc = model.retrieveServiceByName(item['name'])
 				itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + SERVICE
@@ -3455,11 +3446,29 @@
 			except:
 				try:
 					svc = model.retrieveVMsByName(item['name'])
-					itemmap['virt'] = True
+					itemmap['is_vm'] = True
 					itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + VM_CONFIG 
 					itemmap['delurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + VM_CONFIG
 				except:
 					continue
+
+			starturls = list()
+			for node in nodes:
+				if node.getName() != cur_node:
+					starturl = {}
+					cur_nodename = node.getName()
+					starturl['nodename'] = cur_nodename
+					starturl['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_START + '&nodename=' + node.getName()
+					starturls.append(starturl)
+
+					if itemmap.has_key('is_vm') and itemmap['is_vm'] is True:
+						migrate_url = { 'nodename': cur_nodename }
+						migrate_url['migrate'] = True
+						migrate_url['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_MIGRATE + '&nodename=' + node.getName()
+						starturls.append(migrate_url)
+
+			itemmap['links'] = starturls
+
 			dom = svc.getAttribute("domain")
 			if dom is not None:
 				itemmap['faildom'] = dom
@@ -3513,42 +3522,59 @@
 		return hmap
 
 	for item in status:
-		if item['type'] == "service":
+		innermap = {}
+		if item['type'] == 'service':
 			if item['name'] == servicename:
 				hmap['name'] = servicename
-				starturls = list()
 				hmap['autostart'] = item['autostart']
-				if item['running'] == "true":
-					hmap['running'] = "true"
-					#In this case, determine where it can run...
-					innermap = {}
+
+				starturls = list()
+				if item['running'] == 'true':
+					hmap['running'] = 'true'
 					nodename = item['nodename']
-					innermap['current'] = "This service is currently running on %s" % nodename
+					innermap['current'] = 'This service is currently running on %s' % nodename
+
 					innermap['disableurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_STOP
 					innermap['restarturl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_RESTART
 					innermap['delurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_DELETE
 
+					#In this case, determine where it can run...
 					nodes = model.getNodes()
 					for node in nodes:
-						starturl = {}
 						if node.getName() != nodename:
-							starturl['nodename'] = node.getName()
+							starturl = {}
+							cur_nodename = node.getName()
+							starturl['nodename'] = cur_nodename
 							starturl['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START + "&nodename=" + node.getName()
 							starturls.append(starturl)
+
+							if item.has_key('is_vm') and item['is_vm'] is True:
+								migrate_url = { 'nodename': cur_nodename }
+								migrate_url['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_MIGRATE + "&nodename=" + node.getName()
+								migrate_url['migrate'] = True
+								starturls.append(migrate_url)
 					innermap['links'] = starturls
 				else:
 					#Do not set ['running'] in this case...ZPT will detect it is missing
-					#In this case, determine where it can run...
-					innermap = {}
 					innermap['current'] = "This service is currently stopped"
 					innermap['enableurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START
+					innermap['delurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_DELETE
+
 					nodes = model.getNodes()
 					starturls = list()
 					for node in nodes:
 						starturl = {}
-						starturl['nodename'] = node.getName()
+						cur_nodename = node.getName()
+
+						starturl['nodename'] = cur_nodename
 						starturl['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START + "&nodename=" + node.getName()
 						starturls.append(starturl)
+
+						if item.has_key('is_vm') and item['is_vm'] is True:
+							migrate_url = { 'nodename': cur_nodename }
+							migrate_url['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_MIGRATE + "&nodename=" + node.getName()
+							migrate_url['migrate'] = True
+							starturls.append(migrate_url)
 					innermap['links'] = starturls
 				hmap['innermap'] = innermap
 
@@ -3659,14 +3685,72 @@
 
 	batch_number, result = startService(rc, svcname, nodename)
 	if batch_number is None or result is None:
-		luci_log.debug_verbose('startService3: SS(%s,%s,%s) call failed' \
+		luci_log.debug_verbose('serviceStart3: SS(%s,%s,%s) call failed' \
+			% (svcname, cluname, nodename))
+		return None
+
+	try:
+		status_msg = "Starting service \'%s\'" % svcname
+		if nodename:
+			status_msg += " on node \'%s\'" % nodename
+		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, status_msg)
+	except Exception, e:
+		luci_log.debug_verbose('serviceStart4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
+
+	response = req.RESPONSE
+	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
+
+def serviceMigrate(self, rc, req):
+	svcname = None
+	try:
+		svcname = req['servicename']
+	except:
+		try:
+			svcname = req.form['servicename']
+		except:
+			pass
+
+	if svcname is None:
+		luci_log.debug_verbose('serviceMigrate0: no service name')
+		return None
+
+	nodename = None
+	try:
+		nodename = req['nodename']
+	except:
+		try:
+			nodename = req.form['nodename']
+		except:
+			pass
+
+	if nodename is None:
+		luci_log.debug_verbose('serviceMigrate1: no target node name')
+		return None
+		
+	cluname = None
+	try:
+		cluname = req['clustername']
+	except KeyError, e:
+		try:
+			cluname = req.form['clustername']
+		except:
+			pass
+
+	if cluname is None:
+		luci_log.debug_verbose('serviceMigrate2: no cluster name for svc %s' \
+			% svcname)
+		return None
+
+	batch_number, result = migrateService(rc, svcname, nodename)
+	if batch_number is None or result is None:
+		luci_log.debug_verbose('serviceMigrate3: SS(%s,%s,%s) call failed' \
 			% (svcname, cluname, nodename))
 		return None
 
 	try:
-		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, "Starting service \'%s\'" % svcname)
+		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, "Migrating service \'%s\' to node \'%s\'" % (svcname, nodename))
 	except Exception, e:
-		luci_log.debug_verbose('startService4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
+		luci_log.debug_verbose('serviceMigrate4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
 
 	response = req.RESPONSE
 	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
--- conga/luci/site/luci/Extensions/conga_constants.py	2007/03/01 00:39:18	1.36.2.1
+++ conga/luci/site/luci/Extensions/conga_constants.py	2007/03/12 04:24:34	1.36.2.2
@@ -44,8 +44,9 @@
 FENCEDEV="54"
 CLUSTER_DAEMON="55"
 SERVICE_DELETE = '56'
-FENCEDEV_DELETE = "57"
+FENCEDEV_DELETE = '57'
 FENCEDEV_NODE_CONFIG = '58'
+SERVICE_MIGRATE = '59'
 
 CONF_EDITOR = '80'
 
--- conga/luci/site/luci/Extensions/ricci_bridge.py	2007/03/01 00:40:53	1.56.2.4
+++ conga/luci/site/luci/Extensions/ricci_bridge.py	2007/03/12 04:24:34	1.56.2.5
@@ -454,6 +454,12 @@
 	ricci_xml = rc.batch_run(batch_str)
 	return batchAttemptResult(ricci_xml)
 
+def migrateService(rc, servicename, preferrednode):
+	batch_str = '<module name="cluster"><request API_version="1.0"><function_call name="migrate_service"><var mutable="false" name="servicename" type="string" value=\"' + servicename + '\"/><var mutable="false" name="nodename" type="string" value=\"' + preferrednode + '\" /></function_call></request></module>'
+
+	ricci_xml = rc.batch_run(batch_str)
+	return batchAttemptResult(ricci_xml)
+
 def updateServices(rc, enable_list, disable_list):
 	batch = ''
 



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2007-03-12  4:22 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2007-03-12  4:22 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Branch: 	RHEL5
Changes by:	rmccabe at sourceware.org	2007-03-12 04:22:26

Modified files:
	luci/cluster   : form-chooser form-macros 
	luci/site/luci/Extensions: cluster_adapters.py 
	                           conga_constants.py ricci_bridge.py 

Log message:
	Frontend support for virtual service live migration

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.12.2.4&r2=1.12.2.5
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.90.2.20&r2=1.90.2.21
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.120.2.23&r2=1.120.2.24
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.19.2.8&r2=1.19.2.9
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/ricci_bridge.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.30.2.18&r2=1.30.2.19

--- conga/luci/cluster/form-chooser	2007/03/01 00:31:08	1.12.2.4
+++ conga/luci/cluster/form-chooser	2007/03/12 04:22:25	1.12.2.5
@@ -92,6 +92,9 @@
     <span tal:omit-tag="" tal:condition="python: ptype == '28'">
      <div metal:use-macro="here/form-macros/macros/servicerestart"/>
     </span>
+    <span tal:omit-tag="" tal:condition="python: ptype == '59'">
+     <div metal:use-macro="here/form-macros/macros/servicemigrate"/>
+    </span>
     <span tal:omit-tag="" tal:condition="python: ptype == '30'">
      <div metal:use-macro="here/resource-form-macros/macros/resources-form"/>
     </span>
--- conga/luci/cluster/form-macros	2007/03/05 16:50:09	1.90.2.20
+++ conga/luci/cluster/form-macros	2007/03/12 04:22:25	1.90.2.21
@@ -3876,12 +3876,12 @@
 
 			<tr class="cluster service info_top">
 				<td class="cluster service service_name">
-					<strong class="cluster service">Service Name:</strong>
+					<strong class="cluster service">Service Name</strong>
 					<a tal:attributes="
 						href svc/cfgurl;
 						class python: 'cluster service ' + (running and 'running' or 'stopped')"
 						tal:content="svc/name" />
-					<tal:block tal:condition="exists:svc/virt">
+					<tal:block tal:condition="exists:svc/is_vm">
 						(virtual service)
 					</tal:block>
 				</td>
@@ -3898,7 +3898,7 @@
 
 							<option
 								tal:condition="running"
-								tal:attributes="value svc/retstarturl| nothing"
+								tal:attributes="value svc/restarturl | nothing"
 								tal:content="string:Restart this service" />
 
 							<option
@@ -3909,14 +3909,40 @@
 							<option
 								tal:condition="not: running"
 								tal:attributes="value svc/enableurl | nothing"
-								tal:content="string:Start this service" />
+								tal:content="string:Enable this service" />
 
 							<option
 								tal:condition="not: running"
 								tal:attributes="value svc/delurl | nothing"
 								tal:content="string:Delete this service" />
+
 							<option value="">----------</option>
-							<option tal:repeat="starturl svc/links" tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename"/></option>
+
+							<tal:block tal:condition="not: running">
+								<tal:block tal:repeat="starturl svc/links">
+									<option
+										tal:condition="not:exists: starturl/migrate"
+										tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+							</tal:block>
+
+							<tal:block tal:condition="running">
+								<tal:block tal:repeat="starturl svc/links">
+									<option
+										tal:condition="not:exists: starturl/migrate"
+										tal:attributes="value starturl/url">Relocate this service to <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+
+								<tal:block tal:condition="svc/is_vm | nothing">
+									<option value="">----------</option>
+									<tal:block tal:repeat="starturl svc/links">
+										<option
+											tal:condition="exists: starturl/migrate"
+											tal:attributes="value starturl/url">Migrate this service to <span tal:replace="starturl/nodename" /></option>
+									</tal:block>
+								</tal:block>
+							</tal:block>
+
 						</select>
 						<input type="button" value="Go"
 							onclick="if (this.form.gourl[this.form.gourl.selectedIndex].value && confirm(this.form.gourl[this.form.gourl.selectedIndex].text + '?')) return dropdown(this.form.gourl)" />
@@ -4227,10 +4253,19 @@
 
 	<tal:block tal:define="
 		result python: here.serviceStart(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
+<div metal:define-macro="servicemigrate">
+	<script type="text/javascript">
+		set_page_title('Luci ??? cluster ??? services ??? Migrate a virtual service');
+	</script>
+
+	<tal:block tal:define="
+		global ricci_agent ri_agent | python: here.getRicciAgentForCluster(request)" />
+
+	<tal:block tal:define="
+		result python: here.serviceMigrate(ricci_agent, request)" />
+</div>
 
 <div metal:define-macro="servicerestart">
 	<script type="text/javascript">
@@ -4242,8 +4277,6 @@
 
 	<tal:block tal:define="
 		result python: here.serviceRestart(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
 <div metal:define-macro="servicestop">
@@ -4256,8 +4289,6 @@
 
 	<span tal:define="
 		result python: here.serviceStop(ricci_agent, request)" />
-
-	<!-- <span metal:use-macro="here/form-macros/macros/serviceconfig-form"/> -->
 </div>
 
 <div metal:define-macro="serviceconfig-type-macro" tal:omit-tag="">
@@ -4367,22 +4398,51 @@
 
 						<option value="">Choose a Task...</option>
 						<tal:block tal:condition="running">
+							<option
+								tal:attributes="value innermap/restarturl">Restart this service</option>
+
+							<option
+								tal:attributes="value innermap/disableurl">Disable this service</option>
+
 							<option value="">----------</option>
-							<option value="" tal:attributes="value innermap/restarturl">Restart this service</option>
-							<option value="" tal:attributes="value innermap/disableurl">Disable this service</option>
-							<option value="">----------</option>
-							<option tal:repeat="starturl innermap/links" value="" tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename"/></option>
+
+							<tal:block tal:repeat="starturl innermap/links">
+								<option
+									tal:condition="not:exists: starturl/migrate"
+									tal:attributes="value starturl/url">Relocate this service to <span tal:replace="starturl/nodename" />
+								</option>
+							</tal:block>
+
+							<tal:block tal:condition="svc/is_vm | nothing">
+								<option value="">----------</option>
+								<tal:block tal:repeat="starturl innermap/links">
+									<option
+										tal:condition="exists: starturl/migrate"
+										tal:attributes="value starturl/url">Migrate this service to <span tal:replace="starturl/nodename" /></option>
+								</tal:block>
+							</tal:block>
 						</tal:block>
 
 						<tal:block tal:condition="not: running">
+							<option
+								tal:attributes="value innermap/enableurl">Enable this service</option>
 							<option value="">----------</option>
-							<option value="" tal:attributes="value innermap/enableurl">Enable this service</option>
+
+							<tal:block tal:repeat="starturl innermap/links">
+								<option
+									tal:condition="not:exists: starturl/migrate"
+									tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename" />
+								</option>
+							</tal:block>
+
 							<option value="">----------</option>
+
 							<option
 								tal:attributes="value innermap/delurl | nothing"
 								tal:content="string:Delete this service" />
 						</tal:block>
 					</select>
+
 					<input type="button" value="Go"
 						onclick="if (this.form.gourl[this.form.gourl.selectedIndex].value && confirm(this.form.gourl[this.form.gourl.selectedIndex].text + '?')) return dropdown(this.form.gourl)" />
 				</form>
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2007/03/05 16:50:09	1.120.2.23
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2007/03/12 04:22:26	1.120.2.24
@@ -3439,15 +3439,6 @@
 
 			itemmap['autostart'] = item['autostart']
 
-			starturls = list()
-			for node in nodes:
-				starturl = {}
-				if node.getName() != cur_node:
-					starturl['nodename'] = node.getName()
-					starturl['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_START + '&nodename=' + node.getName()
-					starturls.append(starturl)
-			itemmap['links'] = starturls
-
 			try:
 				svc = model.retrieveServiceByName(item['name'])
 				itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + SERVICE
@@ -3455,11 +3446,29 @@
 			except:
 				try:
 					svc = model.retrieveVMsByName(item['name'])
-					itemmap['virt'] = True
+					itemmap['is_vm'] = True
 					itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + VM_CONFIG 
 					itemmap['delurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + VM_CONFIG
 				except:
 					continue
+
+			starturls = list()
+			for node in nodes:
+				if node.getName() != cur_node:
+					starturl = {}
+					cur_nodename = node.getName()
+					starturl['nodename'] = cur_nodename
+					starturl['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_START + '&nodename=' + node.getName()
+					starturls.append(starturl)
+
+					if itemmap.has_key('is_vm') and itemmap['is_vm'] is True:
+						migrate_url = { 'nodename': cur_nodename }
+						migrate_url['migrate'] = True
+						migrate_url['url'] = baseurl + '?' + 'clustername=' + cluname +'&servicename=' + item['name'] + '&pagetype=' + SERVICE_MIGRATE + '&nodename=' + node.getName()
+						starturls.append(migrate_url)
+
+			itemmap['links'] = starturls
+
 			dom = svc.getAttribute("domain")
 			if dom is not None:
 				itemmap['faildom'] = dom
@@ -3513,42 +3522,59 @@
 		return hmap
 
 	for item in status:
-		if item['type'] == "service":
+		innermap = {}
+		if item['type'] == 'service':
 			if item['name'] == servicename:
 				hmap['name'] = servicename
-				starturls = list()
 				hmap['autostart'] = item['autostart']
-				if item['running'] == "true":
-					hmap['running'] = "true"
-					#In this case, determine where it can run...
-					innermap = {}
+
+				starturls = list()
+				if item['running'] == 'true':
+					hmap['running'] = 'true'
 					nodename = item['nodename']
-					innermap['current'] = "This service is currently running on %s" % nodename
+					innermap['current'] = 'This service is currently running on %s' % nodename
+
 					innermap['disableurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_STOP
 					innermap['restarturl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_RESTART
 					innermap['delurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_DELETE
 
+					#In this case, determine where it can run...
 					nodes = model.getNodes()
 					for node in nodes:
-						starturl = {}
 						if node.getName() != nodename:
-							starturl['nodename'] = node.getName()
+							starturl = {}
+							cur_nodename = node.getName()
+							starturl['nodename'] = cur_nodename
 							starturl['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START + "&nodename=" + node.getName()
 							starturls.append(starturl)
+
+							if item.has_key('is_vm') and item['is_vm'] is True:
+								migrate_url = { 'nodename': cur_nodename }
+								migrate_url['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_MIGRATE + "&nodename=" + node.getName()
+								migrate_url['migrate'] = True
+								starturls.append(migrate_url)
 					innermap['links'] = starturls
 				else:
 					#Do not set ['running'] in this case...ZPT will detect it is missing
-					#In this case, determine where it can run...
-					innermap = {}
 					innermap['current'] = "This service is currently stopped"
 					innermap['enableurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START
+					innermap['delurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_DELETE
+
 					nodes = model.getNodes()
 					starturls = list()
 					for node in nodes:
 						starturl = {}
-						starturl['nodename'] = node.getName()
+						cur_nodename = node.getName()
+
+						starturl['nodename'] = cur_nodename
 						starturl['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_START + "&nodename=" + node.getName()
 						starturls.append(starturl)
+
+						if item.has_key('is_vm') and item['is_vm'] is True:
+							migrate_url = { 'nodename': cur_nodename }
+							migrate_url['url'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_MIGRATE + "&nodename=" + node.getName()
+							migrate_url['migrate'] = True
+							starturls.append(migrate_url)
 					innermap['links'] = starturls
 				hmap['innermap'] = innermap
 
@@ -3659,14 +3685,72 @@
 
 	batch_number, result = startService(rc, svcname, nodename)
 	if batch_number is None or result is None:
-		luci_log.debug_verbose('startService3: SS(%s,%s,%s) call failed' \
+		luci_log.debug_verbose('serviceStart3: SS(%s,%s,%s) call failed' \
+			% (svcname, cluname, nodename))
+		return None
+
+	try:
+		status_msg = "Starting service \'%s\'" % svcname
+		if nodename:
+			status_msg += " on node \'%s\'" % nodename
+		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, status_msg)
+	except Exception, e:
+		luci_log.debug_verbose('serviceStart4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
+
+	response = req.RESPONSE
+	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
+
+def serviceMigrate(self, rc, req):
+	svcname = None
+	try:
+		svcname = req['servicename']
+	except:
+		try:
+			svcname = req.form['servicename']
+		except:
+			pass
+
+	if svcname is None:
+		luci_log.debug_verbose('serviceMigrate0: no service name')
+		return None
+
+	nodename = None
+	try:
+		nodename = req['nodename']
+	except:
+		try:
+			nodename = req.form['nodename']
+		except:
+			pass
+
+	if nodename is None:
+		luci_log.debug_verbose('serviceMigrate1: no target node name')
+		return None
+		
+	cluname = None
+	try:
+		cluname = req['clustername']
+	except KeyError, e:
+		try:
+			cluname = req.form['clustername']
+		except:
+			pass
+
+	if cluname is None:
+		luci_log.debug_verbose('serviceMigrate2: no cluster name for svc %s' \
+			% svcname)
+		return None
+
+	batch_number, result = migrateService(rc, svcname, nodename)
+	if batch_number is None or result is None:
+		luci_log.debug_verbose('serviceMigrate3: SS(%s,%s,%s) call failed' \
 			% (svcname, cluname, nodename))
 		return None
 
 	try:
-		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, "Starting service \'%s\'" % svcname)
+		set_node_flag(self, cluname, rc.hostname(), str(batch_number), SERVICE_START, "Migrating service \'%s\' to node \'%s\'" % (svcname, nodename))
 	except Exception, e:
-		luci_log.debug_verbose('startService4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
+		luci_log.debug_verbose('serviceMigrate4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
 
 	response = req.RESPONSE
 	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
--- conga/luci/site/luci/Extensions/conga_constants.py	2007/03/01 00:31:08	1.19.2.8
+++ conga/luci/site/luci/Extensions/conga_constants.py	2007/03/12 04:22:26	1.19.2.9
@@ -44,8 +44,9 @@
 FENCEDEV="54"
 CLUSTER_DAEMON="55"
 SERVICE_DELETE = '56'
-FENCEDEV_DELETE = "57"
+FENCEDEV_DELETE = '57'
 FENCEDEV_NODE_CONFIG = '58'
+SERVICE_MIGRATE = '59'
 
 CONF_EDITOR = '80'
 
--- conga/luci/site/luci/Extensions/ricci_bridge.py	2007/03/01 00:31:08	1.30.2.18
+++ conga/luci/site/luci/Extensions/ricci_bridge.py	2007/03/12 04:22:26	1.30.2.19
@@ -454,6 +454,12 @@
 	ricci_xml = rc.batch_run(batch_str)
 	return batchAttemptResult(ricci_xml)
 
+def migrateService(rc, servicename, preferrednode):
+	batch_str = '<module name="cluster"><request API_version="1.0"><function_call name="migrate_service"><var mutable="false" name="servicename" type="string" value=\"' + servicename + '\"/><var mutable="false" name="nodename" type="string" value=\"' + preferrednode + '\" /></function_call></request></module>'
+
+	ricci_xml = rc.batch_run(batch_str)
+	return batchAttemptResult(ricci_xml)
+
 def updateServices(rc, enable_list, disable_list):
 	batch = ''
 



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2006-12-21 21:26 kupcevic
  0 siblings, 0 replies; 10+ messages in thread
From: kupcevic @ 2006-12-21 21:26 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	kupcevic at sourceware.org	2006-12-21 21:26:20

Modified files:
	luci/cluster   : form-chooser form-macros 
	luci/site/luci/Extensions: cluster_adapters.py 
	                           conga_constants.py 

Log message:
	luci: cluster.conf editor

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&r1=1.14&r2=1.15
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&r1=1.136&r2=1.137
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.191&r2=1.192
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&r1=1.31&r2=1.32

--- conga/luci/cluster/form-chooser	2006/12/06 18:38:53	1.14
+++ conga/luci/cluster/form-chooser	2006/12/21 21:26:20	1.15
@@ -152,6 +152,11 @@
     <span tal:omit-tag="" tal:condition="python: ptype == '55'">
      <div metal:use-macro="here/form-macros/macros/fencedevprocess-form"/>
     </span>
+
+    <span tal:omit-tag="" tal:condition="python: ptype == '80'">
+     <div metal:use-macro="here/form-macros/macros/conf_editor-form"/>
+    </span>
+
    </span>
   </metal:choose-form>
   </body>
--- conga/luci/cluster/form-macros	2006/12/21 05:08:48	1.136
+++ conga/luci/cluster/form-macros	2006/12/21 21:26:20	1.137
@@ -825,7 +825,8 @@
 
 			<tbody class="systemsTable">
 				<tr class="systemsTable">
-					<td class="systemsTable">Post Fail Delay</td>
+					<td class="systemsTable">Post Fail <span tal:attributes="onclick python:'window.location.assign(\'./?pagetype=80&clustername=' + request['clustername'] + '\')'">Delay</span>
+					</td>
 					<td class="systemsTable">
 						<input type="text" name="post_fail_delay"
 							tal:attributes="value clusterinfo/pfd" />
@@ -3871,6 +3872,28 @@
 	<h2>Fence Device Process Form</h2>
 </div>
 
+<div metal:define-macro="conf_editor-form">
+	<h2>Edit cluster.conf</h2>
+	<form method="post"
+	      tal:attributes="action python: './?' + request['QUERY_STRING']"
+	      tal:define="ret python: here.process_cluster_conf_editor(request)">
+	  <span tal:content="structure python: ret['msg'].replace('\n', '<br/>')"/>
+	  <textarea name="new_cluster_conf"
+		          rows="80"
+		          tal:content="structure ret/cluster_conf"></textarea>
+	  <input tal:attributes="type  string:hidden;
+	                         name  string:pagetype;
+	                         value python:request['pagetype']"/>
+	  <input tal:attributes="type  string:hidden;
+	                         name  string:clustername;
+	                         value python:request['clustername']"/>
+	  <input type="button" 
+	         value="Reset"
+	         tal:attributes="onclick python:'window.location.assign(\'./?pagetype=' + request['pagetype'] + '&clustername=' + request['clustername'] + '\')'"/>
+	  <input type="submit" value="Propagate"/>
+	</form>
+</div>
+
 
 </body>
 </html>
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2006/12/21 05:08:49	1.191
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2006/12/21 21:26:20	1.192
@@ -5799,3 +5799,68 @@
 					% (batch_id, task, desc, objpath, str(e))
 		luci_log.debug_verbose(errmsg)
 		raise Exception, errmsg
+
+
+
+
+
+
+
+
+
+
+
+def process_cluster_conf_editor(self, req):
+	clustername = req['clustername']
+	msg = '\n'
+	cc = ''
+	if 'new_cluster_conf' in req:
+		cc = req['new_cluster_conf']
+		msg += 'Checking if valid XML - '
+		cc_xml = None
+		try:
+			cc_xml = minidom.parseString(cc)
+		except:
+			pass
+		if cc_xml == None:
+			msg += 'FAILED\n'
+			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:
+				msg += 'FAILED\n'
+				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:
+					luci_log.debug_verbose('VFA: unable to find a ricci agent for the %s cluster' % clustername)
+					msg += '\nUnable to contact a ricci agent for cluster ' + clustername + '\n\n'
+				else:
+					batch_id, result = setClusterConf(rc, cc_xml.toxml())
+					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:	
+						msg += ' - DONE\n'
+						cc = cc_xml.toxml()
+						msg += '\n\nALL DONE\n\n'
+	else:
+		if getClusterInfo(self, None, req) == {}:
+			msg = 'invalid cluster'
+		else:
+			model = req.SESSION.get('model')
+			cc = model.exportModelAsString()
+	return {'msg'              : msg,
+		'cluster_conf'     : cc}
--- conga/luci/site/luci/Extensions/conga_constants.py	2006/12/21 03:42:49	1.31
+++ conga/luci/site/luci/Extensions/conga_constants.py	2006/12/21 21:26:20	1.32
@@ -46,6 +46,8 @@
 SERVICE_DELETE = '56'
 FENCEDEV_DELETE = "57"
 
+CONF_EDITOR = '80'
+
 #Cluster tasks
 CLUSTER_STOP = '1000'
 CLUSTER_START = '1001'



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2006-12-07 17:54 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2006-12-07 17:54 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Branch: 	RHEL5
Changes by:	rmccabe at sourceware.org	2006-12-07 17:54:31

Modified files:
	luci/cluster   : form-chooser form-macros index_html 
	                 resource-form-macros resource_form_handlers.js 
	luci/homebase  : luci_homebase.css 
	luci/site/luci/Extensions: ClusterNode.py FenceDevice.py 
	                           LuciSyslog.py cluster_adapters.py 
	                           conga_constants.py ricci_bridge.py 

Log message:
	Related: bz217387, bz218040, bz212021

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.12.2.1&r2=1.12.2.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.90.2.6&r2=1.90.2.7
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/index_html.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.20.2.4&r2=1.20.2.5
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/resource-form-macros.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.21.2.2&r2=1.21.2.3
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/resource_form_handlers.js.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.20.2.2&r2=1.20.2.3
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/homebase/luci_homebase.css.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.28.2.1&r2=1.28.2.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/ClusterNode.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.1&r2=1.1.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/FenceDevice.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.2&r2=1.2.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/LuciSyslog.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.2.2.3&r2=1.2.2.4
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.120.2.12&r2=1.120.2.13
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.19.2.2&r2=1.19.2.3
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/ricci_bridge.py.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.30.2.10&r2=1.30.2.11

--- conga/luci/cluster/form-chooser	2006/11/16 19:34:52	1.12.2.1
+++ conga/luci/cluster/form-chooser	2006/12/07 17:54:31	1.12.2.2
@@ -80,6 +80,9 @@
     <span tal:omit-tag="" tal:condition="python: ptype == '25'">
      <div metal:use-macro="here/form-macros/macros/serviceprocess-form"/>
     </span>
+	<tal:block tal:condition="python: ptype == '56'">
+		<div metal:use-macro="here/form-macros/macros/servicedelete-form" />
+	</tal:block>
     <span tal:omit-tag="" tal:condition="python: ptype == '26'">
      <div metal:use-macro="here/form-macros/macros/servicestart"/>
     </span>
--- conga/luci/cluster/form-macros	2006/11/30 22:31:59	1.90.2.6
+++ conga/luci/cluster/form-macros	2006/12/07 17:54:31	1.90.2.7
@@ -77,7 +77,7 @@
 
 	<tal:block tal:condition="python: ricci_agent">
 		<tal:block tal:define="
-			global stat python: here.getClusterStatus(ricci_agent);
+			global stat python: here.getClusterStatus(request, ricci_agent);
 			global cstatus python: here.getClustersInfo(stat, request);
 			global cluster_status python: 'cluster ' + (('running' in cstatus and cstatus['running'] == 'true') and 'running' or 'stopped');"
 	 	/>
@@ -122,14 +122,22 @@
 		</td>
 	</tr>
 
+	<tr class="cluster">
+		<td tal:condition="exists: cstatus/error" class="cluster">
+			<span class="errmsgs">
+				An error occurred while attempting to get status information for this cluster. The information shown may be out of date.
+			</span>
+		</td>
+	</tr>
+
 	<tr class="cluster info_middle">
 		<td colspan="2" class="cluster cluster_quorum">
 			<ul class="cluster_quorum"
 				tal:condition="exists: cstatus/status">
 
-				<li><strong class="cluster">Status</strong>: <span tal:replace="cstatus/status"/></li>
-				<li><strong class="cluster">Total Cluster Votes</strong>: <span tal:replace="cstatus/votes"/></li>
-				<li><strong class="cluster">Minimum Required Quorum</strong>: <span tal:replace="cstatus/minquorum"/></li>
+				<li><strong class="cluster">Status</strong>: <span tal:replace="cstatus/status | string:[unknown]"/></li>
+				<li><strong class="cluster">Total Cluster Votes</strong>: <span tal:replace="cstatus/votes | string:[unknown]"/></li>
+				<li><strong class="cluster">Minimum Required Quorum</strong>: <span tal:replace="cstatus/minquorum | string:[unknown]"/></li>
 			</ul>
 		</td>
 	</tr>
@@ -1141,7 +1149,7 @@
 
 	<div id="fence_apc" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>APC Power Switch</td>
 			</tr>
@@ -1174,6 +1182,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-apc" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_apc" />
 	</div>
 </div>
@@ -1183,7 +1205,7 @@
 
 	<div id="fence_mcdata" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>McData SAN Switch</td>
 			</tr>
@@ -1216,6 +1238,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-mcdata" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_mcdata" />
 	</div>
 </div>
@@ -1225,7 +1261,7 @@
 
 	<div id="fence_wti" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>WTI Power Switch</td>
 			</tr>
@@ -1251,6 +1287,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-wti" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_wti" />
 	</div>
 </div>
@@ -1260,7 +1310,7 @@
 
 	<div id="fence_ilo" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>HP iLO</td>
 			</tr>
@@ -1293,6 +1343,11 @@
 				</td>
 			</tr>
 		</table>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
 		<input type="hidden" name="fence_type" value="fence_ilo" />
 	</div>
 </div>
@@ -1302,7 +1357,7 @@
 
 	<div id="fence_drac" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>Dell Drac</td>
 			</tr>
@@ -1334,6 +1389,11 @@
 						tal:attributes="value cur_fencedev/passwd | nothing" />
 				</td>
 		</table>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
 		<input type="hidden" name="fence_type" value="fence_drac" />
 	</div>
 </div>
@@ -1343,7 +1403,7 @@
 
 	<div id="fence_rsa" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>IBM RSA II</td>
 			</tr>
@@ -1376,6 +1436,11 @@
 				</td>
 			</tr>
 		</table>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
 		<input type="hidden" name="fence_type" value="fence_rsa" />
 	</div>
 </div>
@@ -1385,7 +1450,7 @@
 
 	<div id="fence_brocade" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>Brocade Fabric Switch</td>
 			</tr>
@@ -1418,6 +1483,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-brocade" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_brocade" />
 	</div>
 </div>
@@ -1427,7 +1506,7 @@
 
 	<div id="fence_sanbox2" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>QLogic SANbox2</td>
 			</tr>
@@ -1457,6 +1536,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-sanbox2" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_sanbox2" />
 	</div>
 </div>
@@ -1466,7 +1559,7 @@
 
 	<div id="fence_vixel" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>Vixel SAN Switch</td>
 			</tr>
@@ -1492,6 +1585,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-brocade" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_vixel" />
 	</div>
 </div>
@@ -1501,7 +1608,7 @@
 
 	<div id="fence_gnbd" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>GNBD</td>
 			</tr>
@@ -1520,6 +1627,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-gnbd" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_gnbd" />
 	</div>
 </div>
@@ -1529,7 +1650,7 @@
 
 	<div id="fence_egenera" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>Egenera SAN Controller</td>
 			</tr>
@@ -1555,6 +1676,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-egenera" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_egenera" />
 	</div>
 </div>
@@ -1564,7 +1699,7 @@
 
 	<div id="fence_bladecenter" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>IBM Blade Center</td>
 			</tr>
@@ -1597,6 +1732,11 @@
 				</td>
 			</tr>
 		</table>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
 		<input type="hidden" name="fence_type" value="fence_bladecenter" />
 	</div>
 </div>
@@ -1606,7 +1746,7 @@
 
 	<div id="fence_bullpap" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>Bull PAP</td>
 			</tr>
@@ -1639,6 +1779,20 @@
 				</td>
 			</tr>
 		</table>
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-bullpap" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
 		<input type="hidden" name="fence_type" value="fence_bullpap" />
 	</div>
 </div>
@@ -1648,7 +1802,7 @@
 
 	<div id="fence_rps10" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>RPS10 Serial Switch</td>
 			</tr>
@@ -1670,11 +1824,16 @@
 				<td>Port</td>
 				<td>
 					<input name="port" type="text"
-						tal:attributes="value cur_fencedev/port| nothing" />
+						tal:attributes="value cur_fencedev/port | nothing" />
 				</td>
 			</tr>
 		</table>
-		<input type="hidden" name="fence_type" value="fence_rps10"/>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="fence_type" value="fence_rps10" />
 	</div>
 </div>
 
@@ -1682,8 +1841,8 @@
 	tal:attributes="id cur_fencedev/name | nothing">
 
 	<div id="fence_xvm" class="fencedev">
-	<table>
-			<tr tal:condition="exists: cur_fence_type">
+		<table>
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>Virtual Machine Fencing</td>
 			</tr>
@@ -1694,7 +1853,22 @@
 						tal:attributes="value cur_fencedev/name | nothing" />
 				</td>
 			</tr>
-  </table>	
+		</table>	
+		<div name="instances">
+			<tal:block tal:condition="exists: cur_fence_instances">
+				<tal:block tal:repeat="cur_fence_instance cur_fence_instances">
+					<tal:block
+						metal:use-macro="here/form-macros/macros/fence-instance-form-xvm" />
+				</tal:block>
+			</tal:block>
+		</div>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
+		<input type="hidden" name="fence_type" value="xvm" />
 	</div>
 </div>
 
@@ -1702,8 +1876,8 @@
 	tal:attributes="id cur_fencedev/name | nothing">
 
 	<div id="fence_scsi" class="fencedev">
-	<table>
-			<tr tal:condition="exists: cur_fence_type">
+		<table>
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>SCSI Reservation Fencing</td>
 			</tr>
@@ -1714,7 +1888,14 @@
 						tal:attributes="value cur_fencedev/name | nothing" />
 				</td>
 			</tr>
-  </table>	
+		</table>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="sharable" value="1" />
+		<input type="hidden" name="fence_type" value="scsi" />
 	</div>
 </div>
 
@@ -1723,7 +1904,7 @@
 
 	<div id="fence_ipmilan" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>IPMI Lan</td>
 			</tr>
@@ -1760,6 +1941,11 @@
 				<td><input name="auth_type" type="text" Title="Options are to leave blank for none, password, md2, or md5"/></td>
 			</tr>
 		</table>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
 		<input type="hidden" name="fence_type" value="fence_ipmilan" />
 	</div>
 </div>
@@ -1769,7 +1955,7 @@
 
 	<div id="fence_manual" class="fencedev">
 		<table>
-			<tr tal:condition="exists: cur_fence_type">
+			<tr>
 				<td><strong class="cluster">Fence Type</strong></td>
 				<td>Manual Fencing</td>
 			</tr>
@@ -1780,8 +1966,13 @@
 						tal:attributes="value cur_fencedev/name | nothing" />
 				</td>
 			</tr>
-			<input type="hidden" name="fence_type" value="fence_manual" />
 		</table>
+		<tal:block tal:condition="exists: cur_fencedev">
+			<input type="hidden" name="existing_device" value="1" />
+			<input type="hidden" name="old_name"
+				tal:attributes="value cur_fencedev/name | nothing" />
+		</tal:block>
+		<input type="hidden" name="fence_type" value="fence_manual" />
 	</div>
 </div>
 
@@ -1863,172 +2054,206 @@
 </div>
 
 <div metal:define-macro="fence-instance-form-apc">
-	<div id="fence_apc_instance" class="fencedev">
+	<div id="fence_apc_instance" name="fence_apc" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Port</td>
 				<td>
 					<input name="port" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/port | nothing" />
 				</td>
 			</tr>
 			<tr>
 				<td>Switch</td>
 				<td>
 					<input name="switch" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/switch | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-egenera">
-	<div id="fence_egenera_instance" class="fencedev">
+	<div id="fence_egenera_instance" name="fence_egenera" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>lpan</td>
 				<td>
 					<input name="lpan" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/lpan | nothing" />
 				</td>
 			</tr>
 			<tr>
 				<td>pserver</td>
 				<td>
 					<input name="pserver" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/pserver | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-wti">
-	<div id="fence_wti_instance" class="fencedev">
+	<div id="fence_wti_instance" name="fence_wti" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Port</td>
 				<td>
 					<input name="port" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/port | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-brocade">
-	<div id="fence_brocade_instance" class="fencedev">
+	<div id="fence_brocade_instance" name="fence_brocade" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Port</td>
 				<td>
 					<input name="port" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/port | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-vixel">
-	<div id="fence_vixel_instance" class="fencedev">
+	<div id="fence_vixel_instance" name="fence_vixel" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Port</td>
 				<td>
 					<input name="port" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/port | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-sanbox2">
-	<div id="fence_sanbox2_instance" class="fencedev">
+	<div id="fence_sanbox2_instance" name="fence_sanbox2" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Port</td>
 				<td>
 					<input name="port" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/port | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-mcdata">
-	<div id="fence_mcdata_instance" class="fencedev">
+	<div id="fence_mcdata_instance" name="fence_mcdata" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Port</td>
 				<td>
 					<input name="port" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/port | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-gndb">
-	<div id="fence_gnbd_instance" class="fencedev">
+	<div id="fence_gnbd_instance" name="fence_gnbd" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>IP Address</td>
 				<td>
 					<input name="ipaddress" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/ipaddress | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-bladecenter">
-	<div id="fence_bladecenter_instance" class="fencedev">
+	<div id="fence_bladecenter_instance" name="fence_bladecenter" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Blade</td>
 				<td>
 					<input name="ipaddress" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/ipaddress | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-bullpap">
-	<div id="fence_bullpap_instance" class="fencedev">
+	<div id="fence_bullpap_instance" name="fence_bullpap" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Domain</td>
 				<td>
 					<input name="domain" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/domain | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
 
 <div metal:define-macro="fence-instance-form-xvm">
-	<div id="fence_xvm_instance" class="fencedev">
+	<div id="fence_xvm_instance" name="fence_xvm" class="fencedev_instance">
 		<table>
 			<tr>
 				<td>Domain</td>
 				<td>
 					<input name="domain" type="text"
-						tal:attributes="value nothing" />
+						tal:attributes="value cur_instance/domain | nothing" />
 				</td>
 			</tr>
+			<input tal:condition="exists: cur_instance"
+				type="hidden" name="existing_instance" value="1" />
+			<input type="hidden" name="parent_fencedev" value="" />
 		</table>
 	</div>
 </div>
+
 <div metal:define-macro="fence-instance-form-list">
 	<tal:block
 		metal:use-macro="here/form-macros/macros/fence-instance-form-apc" />
@@ -2071,7 +2296,7 @@
 		global ricci_agent ri_agent | python: here.getRicciAgentForCluster(request)" />
 
 	<tal:block tal:define="
-		global nodestatus python: here.getClusterStatus(ricci_agent);
+		global nodestatus python: here.getClusterStatus(request, ricci_agent);
 		global nodeinfo python: here.getNodeInfo(modelb, nodestatus, request);
 		global status_class python: 'node_' + (nodeinfo['nodestate'] == '0' and 'active' or (nodeinfo['nodestate'] == '1' and 'inactive' or 'unknown'));
 		global cluster_node_status_str python: (nodeinfo['nodestate'] == '0' and 'Cluster member' or (nodeinfo['nodestate'] == '1' and 'Currently not a cluster participant' or 'This node is not responding'));
@@ -2214,79 +2439,91 @@
 
 	<hr/>
 
-	<div id="invisible" class="invisible">
+	<div class="invisible" id="fence_device_list">
 		<tal:block metal:use-macro="here/form-macros/macros/fence-form-list" />
 	</div>
 
-	<table id="fence_devices" class="cluster node fencedev">
-		<tfoot class="fencedev">
-		<tr class="cluster node fencedev"><td class="cluster node fencedev">
-			<input type="button" value="Update fence properties"
-				onClick="validate_fence_properties('fence_devices')" />
-		</td></tr>
+	<div class="invisible" id="shared_fence_devices">
+		<tal:block tal:repeat="cur_fencedev fencedevinfo/fencedevs">
+			<tal:block metal:use-macro="here/form-macros/macros/shared-fence-device-list" />
+		</tal:block>
+	</div>
+
+	<div class="invisible" id="fence_instances">
+		<tal:block metal:use-macro="here/form-macros/macros/fence-instance-form-list" />
+	</div>
+
+	<div id="fence_selection_block" class="invisible">
+		<form name="main_fence_form">
+			<select name="select_div">
+				<option value="fence-form-new-device">------ Use an existing Fence Device ------</option>
+				<tal:block tal:repeat="f fencedevinfo/fencedevs">
+					<option class="shared_fencedev"
+						tal:attributes="value f/name"
+						tal:content="python: f['name'] + ' (' + f['pretty_name'] + ')'"
+					/>
+				</tal:block>
+				<option value="fence-form-new-instance">------ Create a new Fence Device ------</option>
+				<tal:block metal:use-macro="here/form-macros/macros/fence-option-list" />
+			</select>
+			<input type="hidden" name="fence_level" value="" />
+			<input type="hidden" name="fence_num" value="" />
+		</form>
+	</div>
+
+	<table id="fence_devices" class="cluster node fence">
+		<tfoot class="fence">
+			<tr class="cluster node fence"><td class="cluster node fence">
+				<input type="button" value="Update fence properties"
+					onClick="validate_fence_properties('fence_devices')" />
+			</td></tr>
 		</tfoot>
-		<tbody class="fencedev">
-		<tr class="cluster node info_top fencedev">
-			<td class="cluster node fencedev">
-				<span class="fencedev">
+
+		<tbody class="fence">
+		<tr class="cluster node info_top fence">
+			<td class="cluster node fence">
+				<span class="fence">
 					<strong class="cluster node">Main Fencing Method</strong>
 				</span>
 			</td>
 			<td class="cluster node fence_backup">
-				<span class="fencedev">
+				<span class="fence">
 					<strong class="cluster node">Backup Fencing Method</strong>
 				</span>
 			</td>
 		</tr>
 
-		<tr class="cluster node info_top fencedev">
-			<td class="cluster node fence_main fencedev">
-				<tal:block tal:repeat="cur_fencedev fencedevinfo/fencedevs">
-					<div class="invisible" id="shared_fence_devices">
-						<tal:block metal:use-macro="here/form-macros/macros/shared-fence-device-list" />
-					</div>
-				</tal:block>
+		<tr class="cluster node info_top fence">
+			<td class="cluster node fence_main fence"><div class="fence_container">
+				<div id="fence_list_level1">
+					<tal:comment tal:replace="nothing">
+						XXX - fill in any existing fence devices for this node
+						and update the counter number for this level
+					</tal:comment>
+				</div>
 
-				<form name="main_fence_form">
-				<select name="select_div"
-					onChange="swap_fence_div('fence_container',
-								this.options[this.selectedIndex].value)">
-					<option value="fence-form-new-device">------ Use an existing Fence Device ------</option>
-					<tal:block tal:repeat="f fencedevinfo/fencedevs">
-						<option class="shared_fencedev"
-							tal:attributes="value f/name"
-							tal:content="python: f['name'] + ' (' + f['pretty_name'] + ')'"
-						/>
-					</tal:block>
-					<option value="fence-form-new-instance">------ Create a new Fence Device ------</option>
-					<tal:block metal:use-macro="here/form-macros/macros/fence-option-list" />
-				</select>
-				</form>
-				<div id="fence_container">
+				<div class="fence_control">
+					<input type="button" value="Add a fence to this level"
+						onclick="add_node_fence_device(1);" />
 				</div>
-			</td>
-			<td class="cluster node fence_main fencedev">
-				<form name="backup_fence_form">
-				<select name="select_div"
-					onChange="swap_fence_div('fence_container_backup',
-						this.options[this.selectedIndex].value)">
-					<option value="fence-form-new-device">------ Use an existing Fence Device ------</option>
-					<option value="fence-form-new-instance">------ Create a new Fence Device ------</option>
-					<tal:block metal:use-macro="here/form-macros/macros/fence-option-list" />
-				</select>
-				</form>
-				<div id="fence_container_backup">
+			</div></td>
+
+			<td class="cluster node fence_main fence"><div class="fence_container">
+				<div id="fence_list_level2">
+					<tal:comment tal:replace="nothing">
+						XXX - fill in any existing fence devices for this node
+						and update the counter number for this level
+					</tal:comment>
 				</div>
-			</td>
+
+				<div class="fence_control">
+					<input type="button" value="Add a fence to this level"
+						onclick="add_node_fence_device(2)" />
+				</div>
+			</div></td>
 		</tr>
 		</tbody>
 	</table>
-	<script type="text/javascript">
-		swap_fence_div('fence_container',
-			document.main_fence_form.select_div.options[document.main_fence_form.select_div.selectedIndex].value);
-		swap_fence_div('fence_container_backup',
-			document.backup_fence_form.select_div.options[document.backup_fence_form.select_div.selectedIndex].value);
-	</script>
 </div>
 
 <div metal:define-macro="nodes-form">
@@ -2302,7 +2539,7 @@
 		global ricci_agent ri_agent | python: here.getRicciAgentForCluster(request)" />
 
 	<tal:block tal:define="
-		global status python: here.getClusterStatus(ricci_agent);
+		global status python: here.getClusterStatus(request, ricci_agent);
 		global nds python: here.getNodesInfo(modelb, status, request)" />
 
 	<div tal:repeat="nd nds">
@@ -2523,7 +2760,7 @@
 		global ricci_agent ri_agent | python: here.getRicciAgentForCluster(request)" />
 
 	<tal:block tal:define="
-		global svcstatus python: here.getClusterStatus(ricci_agent);
+		global svcstatus python: here.getClusterStatus(request, ricci_agent);
 		global svcinf python: here.getServicesInfo(svcstatus,modelb,request);
 		global svcs svcinf/services" />
 
@@ -2546,9 +2783,31 @@
 					<form method="post" onSubmit="return dropdown(this.gourl)">
 						<select name="gourl">
 							<option value="">Choose a Task...</option>
-							<option value="" tal:attributes="value svc/cfgurl">Configure</option>
+							<option
+								tal:attributes="value svc/cfgurl | nothing"
+								tal:content="string:Configure this service" />
+
 							<option value="">----------</option>
-							<option value="">Delete</option>
+
+							<option
+								tal:condition="running"
+								tal:attributes="value svc/retstarturl| nothing"
+								tal:content="string:Restart this service" />
+
+							<option
+								tal:condition="running"
+								tal:attributes="value svc/disableurl | nothing"
+								tal:content="string:Stop this service" />
+
+							<option
+								tal:condition="not: running"
+								tal:attributes="value svc/enableurl | nothing"
+								tal:content="string:Start this service" />
+
+							<option
+								tal:condition="not: running"
+								tal:attributes="value svc/delurl | nothing"
+								tal:content="string:Delete this service" />
 						</select>
 						<input type="submit" value="Go"/>
 					</form>
@@ -2566,7 +2825,7 @@
 							This service is stopped
 						</tal:block>
 					</div>
-					<p>Autostart is <span tal:condition="not: autostart" tal:replace="string:not" /> enabled for this service</p>
+					<p>Autostart is <span tal:condition="python: autostart.lower() == 'false'" tal:replace="string:not" /> enabled for this service</p>
 				</td>
 			</tr>
 
@@ -2628,6 +2887,14 @@
 						<input type="text" length="20" name="service_name" value="" />
 					</td>
 				</tr>
+				<tr class="systemsTable">
+					<td class="systemsTable">
+						Automatically start this service
+					</td>
+					<td class="systemsTable">
+						<input type="checkbox" name="autostart" checked="checked" />
+					</td>
+				</tr>
 			</table>
 		</form>
 	</div>
@@ -2650,7 +2917,10 @@
 		<input type="hidden" name="uuid" value="toplevel" />
 		<input type="hidden" name="parent_uuid" value="_toplevel" />
 		<input type="hidden" name="tree_level" value="-1" />
+		<input type="hidden" name="svc_name" value="" />
+		<input type="hidden" name="autostart" value="-1" />
 		<input type="hidden" name="form_xml" />
+		<input type="hidden" name="action" value="add" />
 		</form>
 	</div>
 
@@ -2710,30 +2980,46 @@
 </div>
 
 <div metal:define-macro="serviceconfig-type-macro" tal:omit-tag="">
-	<span tal:omit-tag="" tal:condition="python: type == 'ip'">
-		<tal:block metal:use-macro="here/resource-form-macros/macros/ip_macro" />
-	</span>
-	<span tal:omit-tag="" tal:condition="python: type == 'fs'">
-		<tal:block metal:use-macro="here/resource-form-macros/macros/fs_macro" />
-	</span>
-	<span tal:omit-tag="" tal:condition="python: type == 'gfs'">
-		<tal:block metal:use-macro="here/resource-form-macros/macros/gfs_macro" />
-	</span>
-	<span tal:omit-tag="" tal:condition="python: type == 'nfsm'">
-		<tal:block metal:use-macro="here/resource-form-macros/macros/nfsm_macro" />
-	</span>
-	<span tal:omit-tag="" tal:condition="python: type == 'nfsx'">
-		<tal:block metal:use-macro="here/resource-form-macros/macros/nfsx_macro" />
-	</span>
-	<span tal:omit-tag="" tal:condition="python: type == 'nfsc'">
-		<tal:block metal:use-macro="here/resource-form-macros/macros/nfsc_macro" />
-	</span>
-	<span tal:omit-tag="" tal:condition="python: type == 'smb'">
-		<tal:block metal:use-macro="here/resource-form-macros/macros/smb_macro" />
-	</span>
-	<span tal:omit-tag="" tal:condition="python: type == 'script'">
-		<tal:block metal:use-macro="here/resource-form-macros/macros/scr_macro" />
-	</span>
+	<tal:block tal:condition="python: type == 'ip' or type == 'IP Address: '">
+		<tal:block
+			metal:use-macro="here/resource-form-macros/macros/ip_macro" />
+	</tal:block>
+
+	<tal:block tal:condition="python: type == 'fs' or type == 'File System: '">
+		<tal:block
+			metal:use-macro="here/resource-form-macros/macros/fs_macro" />
+	</tal:block>
+
+	<tal:block tal:condition="python: type == 'gfs' or type == 'GFS: '">
+		<tal:block
+			metal:use-macro="here/resource-form-macros/macros/gfs_macro" />
+	</tal:block>
+
+	<tal:block tal:condition="python: type == 'nfsm' or type == 'NFS Mount: '">
+		<tal:block
+			metal:use-macro="here/resource-form-macros/macros/nfsm_macro" />
+	</tal:block>
+
+	<tal:block tal:condition="python: type == 'nfsx' or type == 'NFS Export: '">
+		<tal:block
+			metal:use-macro="here/resource-form-macros/macros/nfsx_macro" />
+	</tal:block>
+
+	<tal:block tal:condition="python: type == 'nfsc' or type == 'NFS Client: '">
+		<tal:block
+			metal:use-macro="here/resource-form-macros/macros/nfsc_macro" />
+	</tal:block>
+
+	<tal:block
+		tal:condition="python: type == 'smb' or type == 'Samba Service: '">
+		<tal:block
+			metal:use-macro="here/resource-form-macros/macros/smb_macro" />
+	</tal:block>
+
+	<tal:block tal:condition="python: type == 'script' or type == 'Script: '">
+		<tal:block
+			metal:use-macro="here/resource-form-macros/macros/scr_macro" />
+	</tal:block>
 </div>
 
 <div metal:define-macro="service-config-head-macro" tal:omit-tag="">
@@ -2749,7 +3035,7 @@
 
 	<tal:block tal:define="
 		global global_resources python: here.getResourcesInfo(modelb, request);
-		global sstat python: here.getClusterStatus(ricci_agent);
+		global sstat python: here.getClusterStatus(request, ricci_agent);
 		global sinfo python: here.getServiceInfo(sstat, modelb, request);
 		global running sinfo/running | nothing;" />
 
@@ -2775,7 +3061,8 @@
 					tal:content="sinfo/name | nothing"
 					tal:attributes="class python: running and 'running' or 'stopped'" />
 			</td>
-			<td class="cluster service service_action">
+			<td class="cluster service service_action"
+				tal:condition="python: sinfo and 'innermap' in sinfo">
 				<form method="post" onSubmit="return dropdown(this.gourl)">
 					<input type="hidden" name="pagetype" tal:attributes="
 						value request/pagetype | request/form/pagetype | nothing" />
@@ -2790,14 +3077,15 @@
 							<option value="" tal:attributes="value innermap/disableurl">Disable this service</option>
 							<option value="">----------</option>
 							<option tal:repeat="starturl innermap/links" value="" tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename"/></option>
-							<option value="">----------</option>
-							<option value="">Delete this service</option>
 						</tal:block>
 
 						<tal:block tal:condition="not: running">
 							<option value="">----------</option>
 							<option value="" tal:attributes="value innermap/enableurl">Enable this service</option>
 							<option value="">----------</option>
+							<option
+								tal:attributes="value innermap/delurl | nothing"
+								tal:content="string:Delete this service" />
 						</tal:block>
 					</select>
 					<input type="submit" value="Go"/>
@@ -2842,6 +3130,18 @@
 		</div>
 	</div>
 	<div class="service_comp_list">
+		<form name="service_name_form">
+			<table class="rescfg">
+				<tr><td>
+				Automatically start this service
+				</td>
+				<td><input type="checkbox" name="autostart"
+						tal:attributes="checked python: ('autostart' in sinfo and sinfo['autostart'].lower() != 'false') and 'checked'" /></td></tr>
+			</table>
+			<input type="hidden" name="service_name"
+				tal:attributes="value sinfo/name | string:1" />
+		</form>
+
 		<form name="master" method="post">
 		<tal:block
 			tal:define="global clusterinfo python: here.getClusterInfo(modelb, request)" />
@@ -2857,7 +3157,10 @@
 		<input type="hidden" name="uuid" value="toplevel" />
 		<input type="hidden" name="parent_uuid" value="_toplevel" />
 		<input type="hidden" name="tree_level" value="-1" />
+		<input type="hidden" name="svc_name" value="" />
+		<input type="hidden" name="autostart" value="-1" />
 		<input type="hidden" name="form_xml" />
+		<input type="hidden" name="action" value="edit" />
 		</form>
 	</div>
 
@@ -2881,6 +3184,11 @@
 	<h2>Service Process Form</h2>
 </div>
 
+<div metal:define-macro="servicedelete-form">
+	<h2>Service Delete Form</h2>
+	<tal:block tal:define="dummy python: here.delService(request)" />
+</div>
+
 <div metal:define-macro="resources-form">
 	<h2>Resources Form</h2>
 </div>
@@ -2918,7 +3226,7 @@
 		global ricci_agent ri_agent | python: here.getRicciAgentForCluster(request)" />
 
 	<tal:block tal:define="
-		global sta python: here.getClusterStatus(ricci_agent);
+		global sta python: here.getClusterStatus(request, ricci_agent);
 		global fdominfo python: here.getFdomsInfo(modelb, request, sta);" />
 
 	<div class="cluster fdom" tal:repeat="fdom fdominfo">
@@ -3051,23 +3359,23 @@
 		<tal:block metal:use-macro="here/form-macros/macros/shared-fence-form-list" />
 	</div>
 
-	<table id="fence_devices" class="cluster node fencedev">
-		<tfoot class="fencedev">
-		<tr class="cluster node fencedev"><td class="cluster node fencedev">
+	<table id="fence_devices" class="cluster node fence">
+		<tfoot class="fence">
+		<tr class="cluster node fence"><td class="cluster node fence">
 			<input type="button" value="Add this shared fence device"
 				onClick="validate_fence_properties('fence_devices')" />
 		</td></tr>
 		</tfoot>
-		<tbody class="fencedev">
-		<tr class="cluster node info_top fencedev">
-			<td class="cluster node fencedev">
-				<span class="fencedev">
+		<tbody class="fence">
+		<tr class="cluster node info_top fence">
+			<td class="cluster node fence">
+				<span class="fence">
 					<strong class="cluster node">Fencing Type</strong>
 				</span>
 			</td>
 		</tr>
-		<tr class="cluster node info_top fencedev">
-			<td class="cluster node fence_main fencedev">
+		<tr class="cluster node info_top fence">
+			<td class="cluster node fence_main fence">
 				<form name="main_fence_form">
 				<select name="select_div"
 					onChange="swap_fence_div('fence_container',
@@ -3208,7 +3516,7 @@
 		<tal:block metal:use-macro="here/form-macros/macros/fence-form-manual" />
 	</tal:block>
 
-	<div class="fencedev">
+	<div class="fence_submit">
 		<input class="hbInput" type="button" value="Submit" name="Submit" />
 	</div>
 	</div>
--- conga/luci/cluster/index_html	2006/11/16 19:34:52	1.20.2.4
+++ conga/luci/cluster/index_html	2006/12/07 17:54:31	1.20.2.5
@@ -100,25 +100,6 @@
         window.open(href, windowname, 'width=500,height=500,scrollbars=yes');
         return false;
         }
-
-		function swap_fence_div(container_id, element_id) {
-			var container_element = document.getElementById(container_id)
-			if (!container_element) {
-				alert('Can\'t find element with id = ' + container_id);
-				return (-1);
-			}
-
-			var child_element = document.getElementById(element_id);
-			if (!child_element) {
-				alert('Can\'t find element with id = ' + element_id);
-				return (-1);
-			}
-			if (container_element.firstChild)
-				container_element.removeChild(container_element.firstChild);
-			var target = child_element.cloneNode(1);
-			target.id = null;
-			container_element.appendChild(target);
-		}
         //-->
        </SCRIPT>
       <metal:javascriptslot define-slot="javascript_head_slot" />
--- conga/luci/cluster/resource-form-macros	2006/11/16 19:34:53	1.21.2.2
+++ conga/luci/cluster/resource-form-macros	2006/12/07 17:54:31	1.21.2.3
@@ -271,7 +271,7 @@
 			<div metal:use-macro="here/resource-form-macros/macros/fs_macro" />
 		</tal:block>
 
-		<tal:block tal:condition="python: type == 'gfs'">
+		<tal:block tal:condition="python: type == 'gfs' or type == 'clusterfs'">
 			<div metal:use-macro="here/resource-form-macros/macros/gfs_macro" />
 		</tal:block>
 
@@ -307,7 +307,10 @@
 		tal:attributes="name res/parent_uuid | nothing"
 		tal:define="editDisabled resourceIsRef | nothing">
 
-	<input name="edit" type="hidden"
+	<input name="immutable" type="hidden" value="true"
+		tal:condition="editDisabled" />
+
+	<input name="edit" type="hidden" value="true"
 		tal:condition="python: ptype == '33' and True or False" />
 
 	<input name="pagetype" type="hidden"
@@ -368,7 +371,10 @@
 		tal:attributes="name res/parent_uuid | nothing"
 		tal:define="editDisabled resourceIsRef | nothing">
 
-	<input name="edit" type="hidden"
+	<input name="immutable" type="hidden" value="true"
+		tal:condition="editDisabled" />
+
+	<input name="edit" type="hidden" value="true"
 		tal:condition="python: ptype == '33' and True or False" />
 
 	<input name="pagetype" type="hidden"
@@ -507,7 +513,10 @@
 		tal:attributes="name res/parent_uuid | nothing"
 		tal:define="editDisabled resourceIsRef | nothing">
 
-	<input name="edit" type="hidden"
+	<input name="immutable" type="hidden" value="true"
+		tal:condition="editDisabled" />
+
+	<input name="edit" type="hidden" value="true"
 		tal:condition="python: ptype == '33' and True or False" />
 
 	<input name="pagetype" type="hidden"
@@ -609,7 +618,10 @@
 		tal:attributes="name res/parent_uuid | nothing"
 		tal:define="editDisabled resourceIsRef | nothing">
 
-	<input name="edit" type="hidden"
+	<input name="immutable" type="hidden" value="true"
+		tal:condition="editDisabled" />
+
+	<input name="edit" type="hidden" value="true"
 		tal:condition="python: ptype == '33' and True or False" />
 
 	<input name="pagetype" type="hidden"
@@ -727,7 +739,10 @@
 		tal:attributes="name res/parent_uuid | nothing"
 		tal:define="editDisabled resourceIsRef | nothing">
 
-	<input name="edit" type="hidden"
+	<input name="immutable" type="hidden" value="true"
+		tal:condition="editDisabled" />
+
+	<input name="edit" type="hidden" value="true"
 		tal:condition="python: ptype == '33' and True or False" />
 
 	<input name="pagetype" type="hidden"
@@ -799,7 +814,10 @@
 		tal:attributes="name res/parent_uuid | nothing"
 		tal:define="editDisabled resourceIsRef | nothing">
 
-	<input name="edit" type="hidden"
+	<input name="immutable" type="hidden" value="true"
+		tal:condition="editDisabled" />
+
+	<input name="edit" type="hidden" value="true"
 		tal:condition="python: ptype == '33' and True or False" />
 
 	<input name="pagetype" type="hidden"
@@ -851,7 +869,10 @@
 		tal:attributes="name res/parent_uuid | nothing"
 		tal:define="editDisabled resourceIsRef | nothing">
 
-	<input name="edit" type="hidden"
+	<input name="immutable" type="hidden" value="true"
+		tal:condition="editDisabled" />
+
+	<input name="edit" type="hidden" value="true"
 		tal:condition="python: ptype == '33' and True or False" />
 
 	<input name="pagetype" type="hidden"
@@ -913,7 +934,10 @@
 		tal:attributes="name res/parent_uuid | nothing"
 		tal:define="editDisabled resourceIsRef | nothing">
 
-	<input name="edit" type="hidden"
+	<input name="immutable" type="hidden" value="true"
+		tal:condition="editDisabled" />
+
+	<input name="edit" type="hidden" value="true"
 		tal:condition="python: ptype == '33' and True or False" />
 
 	<input name="pagetype" type="hidden"
--- conga/luci/cluster/resource_form_handlers.js	2006/11/16 19:34:53	1.20.2.2
+++ conga/luci/cluster/resource_form_handlers.js	2006/12/07 17:54:31	1.20.2.3
@@ -380,21 +380,61 @@
 function forms_to_xml(master_form) {
 	var errors = new Array();
 	var form_xml = '';
+	var svc_name = null;
+	var autostart = 1;
 
 	var form = document.getElementsByTagName('form');
 	for (var i = 0 ; i < form.length ; i++) {
+		if (form[i].name == 'service_name_form') {
+			if (!form[i].service_name ||
+				str_is_blank(form[i].service_name.value))
+			{
+				set_form_err(form[i].service_name);
+			} else {
+				clr_form_err(form[i].service_name);
+				svc_name = form[i].service_name.value;
+			}
+			if (!form[i].autostart.checked)
+				autostart = 0;
+			continue;
+		}
+
 		if (form[i].name == 'master' || !form[i].uuid || !form[i].uuid.value)
 			continue;
+
 		var err = check_form(form[i]);
 		if (err)
-			errors.concat(err);
-		var temp = form[i].innerHTML.match(/<input [^>]+>/ig).toString().replace(/>(,|$)/g, '/>');
-		if (!temp)
-			continue;
+			errors = errors.concat(err);
+		var temp = '';
+
+		var input_elem = form[i].getElementsByTagName('input');
+		for (var j = 0 ; j < input_elem.length ; j++) {
+			var res_type = input_elem[j].type;
+			if (res_type == 'hidden' || res_type == 'text' ||
+				res_type == 'password')
+			{
+				temp += '<input type="' + res_type + '" name="' + input_elem[j].name + '" value="' + input_elem[j].value + '" />';
+			} else if (res_type == 'checkbox' || res_type == 'radio') {
+				if (input_elem[j].checked)
+					temp += '<input type="' + res_type + '" name="' + input_elem[j].name + '" checked="checked"';
+				if (res_type == 'radio')
+					temp += ' value="' + input_elem[j].value + '"';
+				temp += ' />';
+			}
+		}
+
+		var select_elem = form[i].getElementsByTagName('select');
+		for (var j = 0 ; j < select_elem.length ; j++) {
+			temp += '<input type="text" name="' + select_elem[j].name + '" value="' + select_elem[j].options[select_elem[j].options.selectedIndex].value + '" />';
+		}
+
 		form_xml += '<form id="' + form[i].uuid.value + '" parent="' +
 					form[i].parent_uuid.value + '">' + temp + '</form>';
 	}
 
+	if (!svc_name)
+		errors.push('No name was given for this service.');
+
 	if (!form_xml)
 		errors.push('No resource information was submitted.');
 
@@ -403,7 +443,15 @@
 
 	/* sort this out in the backend */
 	master_form.form_xml.value = '<formlist>' + form_xml + '</formlist>';
-	if (confirm('Save changes to this service?'))
+	master_form.svc_name.value = svc_name;
+	master_form.autostart.value = autostart;
+
+	var confirm_msg = null;
+	if (master_form.action.value == 'add')
+		confirm_msg = 'Create this service?';
+	else
+		confirm_msg = 'Save changes to this service?';
+	if (confirm(confirm_msg))
 		master_form.submit();
 	return (0);
 }
--- conga/luci/homebase/luci_homebase.css	2006/11/16 19:34:53	1.28.2.1
+++ conga/luci/homebase/luci_homebase.css	2006/12/07 17:54:31	1.28.2.2
@@ -14,27 +14,27 @@
 	background: #dee7ec;
 }
 
-div.fencedev {
+div.fence {
 	max-width: 700px;
 	padding: .5em;
 }
 
-*.fencedev {
+*.fence {
 	background: #dee7ec;
 }
 
-table.fencedev {
+table.fence {
 	padding: .618em;
 	width: 700px;
 }
 
-div.fencedev,
-td.fencedev {
+div.fence,
+td.fence {
 	padding-top: .309em;
 	padding-bottom: .309em;
 }
 
-td.fencedev {
+td.fence {
 	width: 50%;
 }
 
@@ -438,6 +438,21 @@
 	margin-bottom: .25em ! important;
 }
 
+div.fence_add {
+	margin-top: .25em ! important;
+	margin-bottom: .25em ! important;
+}
+
+div.fence_container {
+	border: thin solid #c9c9c9;
+}
+
+div.fence_control {
+	margin-top: 2em;
+	margin-bottom: .75em;
+	margin-left: .33em;
+}
+
 div.service_comp_list {
 	background: #dee7ec;
 	max-width: 700px;
--- conga/luci/site/luci/Extensions/ClusterNode.py	2006/05/30 20:17:21	1.1
+++ conga/luci/site/luci/Extensions/ClusterNode.py	2006/12/07 17:54:31	1.1.2.1
@@ -96,3 +96,10 @@
     except KeyError, e:
       return ""
 
+  def getVotes(self):
+    try:
+      return self.getAttribute('votes')
+    except KeyError, e:
+      return "1"
+    except:
+      return None
--- conga/luci/site/luci/Extensions/FenceDevice.py	2006/10/04 15:11:10	1.2
+++ conga/luci/site/luci/Extensions/FenceDevice.py	2006/12/07 17:54:31	1.2.2.1
@@ -19,7 +19,12 @@
 
 
   def getAgentType(self):
-    return self.attr_hash["agent"]
+    agent = self.attr_hash["agent"]
+    try:
+      return agent[agent.rfind('/') + 1:]
+    except:
+      pass
+    return agent
 
   def isShared(self):
     agent = self.getAgentType()
--- conga/luci/site/luci/Extensions/LuciSyslog.py	2006/11/16 19:34:53	1.2.2.3
+++ conga/luci/site/luci/Extensions/LuciSyslog.py	2006/12/07 17:54:31	1.2.2.4
@@ -78,6 +78,7 @@
 
 	def close(self):
 		try:
+			self.__init = 0
 			closelog()
 		except:
 			pass
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2006/11/30 20:12:38	1.120.2.12
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2006/12/07 17:54:31	1.120.2.13
@@ -12,8 +12,10 @@
 from Ip import Ip
 from Clusterfs import Clusterfs
 from Fs import Fs
+from RefObject import RefObject
 from NFSClient import NFSClient
 from NFSExport import NFSExport
+from Service import Service
 from Netfs import Netfs
 from Vm import Vm
 from Script import Script
@@ -396,19 +398,31 @@
 	response.redirect(request['URL'] + "?pagetype=" + CLUSTER_CONFIG + "&clustername=" + clusterName + '&busyfirst=true')
 
 def validateServiceAdd(self, request):
+	errors = list()
+
 	try:
 		form_xml = request['form_xml']
 		if not form_xml:
-			raise KeyError('form_xml must not be blank')
-	except KeyError, e:
+			raise KeyError, 'form_xml must not be blank'
+	except Exception, e:
+		luci_log.debug_verbose('vSA0: no form_xml: %s' % str(e))
 		return (False, {'errors': ['No resource data was supplied for this service.']})
 
 	try:
+		model = request.SESSION.get('model')
+		if not model:
+			raise Exception, 'model is None'
+	except Exception, e:
+		luci_log.debug_verbose('vSA0a: %s' % str(e))
+		return (False, {'errors': [ 'The cluster model is missing from the session object.' ]})
+
+	try:
 		doc = minidom.parseString(form_xml)
 		forms = doc.getElementsByTagName('form')
 		if len(forms) < 1:
 			raise
-	except:
+	except Exception, e:
+		luci_log.debug_verbose('vSA1: error: %s' % str(e))
 		return (False, {'errors': ['The resource data submitted for this service is not properly formed.']})
 
 	form_hash = {}
@@ -440,27 +454,145 @@
 			try:
 				dummy_form[str(i.getAttribute('name'))] = str(i.getAttribute('value'))
 			except Exception, e:
-				luci_log.debug_verbose('Error parsing service XML: %s' % str(e))
+				luci_log.debug_verbose('vSA2: parsing XML: %s' % str(e))
 				pass
 
 		try:
 			res_type = dummy_form['type'].strip()
-			if not res_type or not res_type in resourceAddHandler:
-				raise
-		except:
-			return (False, {'errors': ['An invalid resource type was specified: ' + res_type]})
+			if not res_type:
+				raise Exception, 'no resource type was given'
+			if not res_type in resourceAddHandler:
+				raise Exception, 'invalid resource type: %s' % res_type
+		except Exception, e:
+			luci_log.debug_verbose('vSA3: %s' % str(e))
+			return (False, {'errors': [ 'An invalid resource type was specified' ]})
 
 		try:
-			resObj = resourceAddHandler[res_type](request, dummy_form)
-		except:
-			luci_log('res type %d is invalid' % res_type)
+			if res_type == 'ip':
+				dummy_form['resourceName'] = dummy_form['ip_address']
+		except Exception, e:
+			luci_log.debug_verbose('vSA3a: type is ip but no addr: %s' % str(e))
+			return (False, {'errors': [ 'No IP address was given.' ]})
+
+		try:
+			if dummy_form.has_key('immutable'):
+				newRes = getResource(model, dummy_form['resourceName'])
+				resObj = RefObject(newRes)
+				resObj.setRef(newRes.getName())
+			else:
+				resObj = resourceAddHandler[res_type](request, dummy_form)[0]
+		except Exception, e:
 			resObj = None
+			luci_log.debug_verbose('vSA4: type %s: %s' % (res_type, str(e)))
 
 		if resObj is None:
-			return (False, {'errors': ['An error occurred while adding ' + res_type]})
+			return (False, {'errors': [ 'An error occurred while adding %s' % res_type ]})
 		form_hash[form_id]['obj'] = resObj
-			
-	return (True, {'messages': ['This service has been updated.']})
+
+	if len(errors) > 0:
+		return (False, {'errors': errors})
+
+	try:
+		service_name = request.form['svc_name'].strip()
+	except Exception, e:
+		luci_log.debug_verbose('vSA5: no service name: %s' % str(e))
+		return (False, {'errors': [ 'No service name was given.' ]})
+
+	autostart = "1"
+	try:
+		if not request.form.has_key('autostart') or request.form['autostart'] == "0":
+			autostart = "0"
+	except Exception, e:
+		autostart = None
+		luci_log.debug_verbose('vSA5a: error getting autostart: %s' % str(e))
+
+	try:
+		cur_service = model.retrieveServiceByName(service_name)
+	except GeneralError, e:
+		luci_log.debug_verbose('vSA5b: no service named %s found' % service_name)
+		cur_service = None
+	except Exception, e:
+		luci_log.debug_verbose('vSA5c: no service named %s found: %s' % (service_name, str(e)))
+		cur_service = None
+
+	try:
+		if request.form['action'] == 'edit':
+			if cur_service is None:
+				return (False, {'errors': [ 'The service %s could not be found for editing.' % service_name ]})
+			model.deleteService(service_name)
+		elif request.form['action'] == 'add':
+			if cur_service is not None:
+				return (False, {'errors': [ 'A service with the name %s already exists.' % service_name ]})
+		else:
+			luci_log.debug_verbose('vSA4a: unknown action %s' % request.form['action'])
+			return (False, {'errors': [ 'An unknown action was specified.' ]})
+	except Exception, e:
+		luci_log.debug_verbose('vSA5: no action type: %s' % str(e))
+
+	def buildSvcTree(parent, child_id_list):
+		for i in child_id_list:
+			try:
+				child = form_hash[i]['obj']
+				if not child:
+					raise Exception, 'No object for %s' % i
+			except Exception, e:
+				luci_log.debug_verbose('bST0: %s' % str(e))
+				continue
+			parent.addChild(child)
+			if 'kids' in form_hash[i]:
+				buildSvcTree(child, form_hash[i]['kids'])
+
+	new_service = Service()
+	new_service.addAttribute('name', service_name)
+	if autostart is not None:
+		new_service.attr_hash['autostart'] = autostart
+
+	buildSvcTree(new_service, form_hash['toplevel']['kids'])
+	model.resourcemanager_ptr.addChild(new_service)
+
+	clustername = model.getClusterName()
+	if not clustername:
+		luci_log.debug_verbose('vAS6: no cluname from mb')
+		return (False, {'errors': [ 'Unable to determine cluster name' ]})
+
+	try:
+		conf = model.exportModelAsString()
+		if not conf:
+			raise Exception, 'model string for %s is blank' % clustername
+	except Exception, e:
+		luci_log.debug_verbose('vAS6a: exportModelAsString : %s' \
+			% str(e))
+		return (False, {'errors': [ 'An error occurred while adding this service.' ]})
+
+	rc = getRicciAgent(self, clustername)
+	if not rc:
+		luci_log.debug_verbose('vAS6b: unable to find a ricci agent for cluster %s' % clustername)
+		return 'Unable to find a ricci agent for the %s cluster' % clustername
+
+	try:
+		ragent = rc.hostname()
+		if not ragent:
+			luci_log.debug_verbose('vAS7: missing ricci hostname')
+			raise Exception, 'unknown ricci agent hostname'
+
+		batch_number, result = setClusterConf(rc, str(conf))
+		if batch_number is None or result is None:
+			luci_log.debug_verbose('vAS8: missing batch_number or result')
+			raise Exception, 'unable to save the new cluster configuration.'
+	except Exception, e:
+		luci_log.debug_verbose('vAS9: %s' % str(e))
+		return 'An error occurred while propagating the new cluster.conf: %s' % str(e)
+
+	try:
+		if request.form['action'] == 'edit':
+			set_node_flag(self, clustername, ragent, str(batch_number), SERVICE_CONFIG, "Configuring service \'%s\'" % service_name)
+		else:
+			set_node_flag(self, clustername, ragent, str(batch_number), SERVICE_ADD, "Adding new service \'%s\'" % service_name)
+	except Exception, e:
+		luci_log.debug_verbose('vAS10: failed to set flags: %s' % str(e))
+
+	response = request.RESPONSE
+	response.redirect(request['URL'] + "?pagetype=" + SERVICES + "&clustername=" + clustername + '&busyfirst=true')
 
 def validateResourceAdd(self, request):
 	try:
@@ -1712,23 +1844,133 @@
 		return None
 	return getRicciAgent(self, clustername)
 
-def getClusterStatus(self, rc):
+def getClusterStatusModel(model):
+	results = list()
+	vals = {}
+
+	try:
+		clustername = model.getClusterName()
+		clusteralias = model.getClusterAlias()
+		vals['type'] = 'cluster'
+		vals['alias'] = clusteralias
+		vals['name'] = clustername
+		vals['error'] = True
+		vals['votes'] = '[unknown]'
+		vals['quorate'] = '[unknown]'
+		vals['minQuorum'] = '[unknown]'
+		results.append(vals)
+	except Exception, e:
+		luci_log.debug_verbose('GCSM0: %s' % str(e))
+		return None
+
+	try:
+		nodelist = model.getNodes()
+	except Exception, e:
+		luci_log.debug_verbose('GCSM1: %s' % str(e))
+		return None
+
+	for node in nodelist:
+		node_val = {}
+		node_val['type'] = 'node'
+		try:
+			node_name = node.getName()
+			if not node_name:
+				raise Exception, 'cluster node name is unknown'
+		except:
+			node_name = '[unknown]'
+
+		node_val['name'] = node_name
+		node_val['clustered'] = '[unknown]'
+		node_val['online'] = '[unknown]'
+		node_val['error'] = True
+
+		try:
+			votes = node.getVotes()
+			if not votes:
+				raise Exception, 'unknown unmber of votes'
+		except:
+			votes = '[unknown]'
+
+		node_val['votes'] = votes
+		results.append(node_val)
+	return results
+
+def getClusterStatusDB(self, clustername):
+	results = list()
+	vals = {}
+
+	vals['type'] = 'cluster'
+	vals['alias'] = clustername
+	vals['name'] = clustername
+	vals['error'] = True
+	vals['quorate'] = '[unknown]'
+	vals['votes'] = '[unknown]'
+	vals['minQuorum'] = '[unknown]'
+	results.append(vals)
+
+	try:
+		cluster_path = '%s/luci/systems/cluster/%s' % (CLUSTER_FOLDER_PATH, clustername)
+		nodelist = self.restrictedTraverse(cluster_path).objectItems('Folder')
+	except Exception, e:
+		luci_log.debug_verbose('GCSDB0: %s: %s' % (clustername, str(e)))
+		return results
+
+	for node in nodelist:
+		try:
+			node_val = {}
+			node_val['type'] = 'node'
+			node_val['name'] = node[0]
+			node_val['clustered'] = '[unknown]'
+			node_val['online'] = '[unknown]'
+			node_val['error'] = True
+			results.append(node_val)
+		except Exception, e:
+			luci_log.debug_verbose('GCSDB1: %s' % str(e))
+	return results
+
+def getClusterStatus(self, request, rc):
 	try:
 		doc = getClusterStatusBatch(rc)
+		if not doc:
+			raise Exception, 'doc is None'
 	except Exception, e:
 		luci_log.debug_verbose('GCS0: error: %s' % str(e))
 		doc = None
 
+	if doc is None:
+		try:
+			model = request.SESSION.get('model')
+			cinfo = getClusterStatusModel(model)
+			if not cinfo or len(cinfo) < 1:
+				raise Exception, 'cinfo is None'
+			return cinfo
+		except Exception, e:
+			luci_log.debug_verbose('GCS1: %s' % str(e))
+			doc = None
+
 	if not doc:
 		try:
-			luci_log.debug_verbose('GCS1: returned None for %s/%s' % rc.cluster_info())
-		except:
-			pass
+			clustername = None
+			try:
+				clustername = request['clustername']
+			except:
+				try:
+					clustername = request.form['clustername']
+				except:
+					pass
 
-		return {}
+			if not clustername:
+				raise Exception, 'unable to determine cluster name'
 
-	results = list()
+			cinfo = getClusterStatusDB(self, clustername)
+			if not cinfo or len(cinfo) < 1:
+				raise Exception, 'cinfo is None'
+			return cinfo
+		except Exception, e:
+			luci_log.debug_verbose('GCS1a: unable to get cluster info from DB: %s' % str(e))
+		return []
 
+	results = list()
 	vals = {}
 	vals['type'] = "cluster"
 
@@ -1796,6 +2038,7 @@
 				itemmap['nodename'] = item['nodename']
 			itemmap['autostart'] = item['autostart']
 			itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + SERVICE
+			itemmap['delurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + SERVICE_DELETE
 
 			svc = modelb.retrieveServiceByName(item['name'])
 			dom = svc.getAttribute("domain")
@@ -1847,6 +2090,7 @@
 			if item['name'] == servicename:
 				hmap['name'] = servicename
 				starturls = list()
+				hmap['autostart'] = item['autostart']
 				if item['running'] == "true":
 					hmap['running'] = "true"
 					#In this case, determine where it can run...
@@ -1855,6 +2099,8 @@
 					innermap['current'] = "This service is currently running on %s" % nodename
 					innermap['disableurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_STOP
 					innermap['restarturl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_RESTART
+					innermap['delurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_DELETE
+
 					nodes = modelb.getNodes()
 					for node in nodes:
 						starturl = {}
@@ -1901,16 +2147,18 @@
 	if parent is not None:
 		rc_map['parent'] = parent
 	rc_map['name'] = child.getName()
+
+	#Note: Final version needs all resource attrs
 	if child.isRefObject() == True:
 		rc_map['ref_object'] = True
 		rc_map['type'] = child.getObj().getResourceType()
+		rc_map['attrs'] = child.getObj().getAttributes()
 	else:
 		rc_map['type'] = child.getResourceType()
+		rc_map['attrs'] = child.getAttributes()
 
 	rc_map['indent_ctr'] = indent_ctr
 
-	#Note: Final version needs all resource attrs
-	rc_map['attrs'] = child.getAttributes()
 	rc_map['uuid'] = make_uuid('resource')
 	rc_map['parent_uuid'] = parent_uuid
 
@@ -2186,39 +2434,31 @@
         return {}
 
   if model is None:
-    rc = getRicciAgent(self, cluname)
-    if not rc:
-      luci_log.debug_verbose('GCI1: unable to find a ricci agent for the %s cluster' % cluname)
-      return {}
     try:
-      model = getModelBuilder(None, rc, rc.dom0())
+      model = getModelForCluster(self, cluname)
       if not model:
         raise Exception, 'model is none'
-
-      try:
-        req.SESSION.set('model', model)
-      except Exception, e2:
-        luci_log.debug_verbose('GCI2 unable to set model in session: %s' % str(e2))
+      req.SESSION.set('model', model)
     except Exception, e:
-      luci_log.debug_verbose('GCI3: unable to get model for cluster %s: %s' % (cluname, str(e)))
+      luci_log.debug_verbose('GCI1: unable to get model for cluster %s: %s' % (cluname, str(e)))
       return {}
 
   prop_baseurl = req['URL'] + '?' + PAGETYPE + '=' + CLUSTER_CONFIG + '&' + CLUNAME + '=' + cluname + '&'
-  map = {}
+  clumap = {}
   basecluster_url = prop_baseurl + PROPERTIES_TAB + "=" + PROP_GENERAL_TAB
   #needed:
-  map['basecluster_url'] = basecluster_url
+  clumap['basecluster_url'] = basecluster_url
   #name field
-  map['clustername'] = model.getClusterAlias()
+  clumap['clustername'] = model.getClusterAlias()
   #config version
   cp = model.getClusterPtr()
-  map['config_version'] = cp.getConfigVersion()
+  clumap['config_version'] = cp.getConfigVersion()
   #-------------
   #new cluster params - if rhel5
   #-------------
   #Fence Daemon Props
   fencedaemon_url = prop_baseurl + PROPERTIES_TAB + "=" + PROP_FENCE_TAB
-  map['fencedaemon_url'] = fencedaemon_url
+  clumap['fencedaemon_url'] = fencedaemon_url
   fdp = model.getFenceDaemonPtr()
   pjd = fdp.getAttribute('post_join_delay')
   if pjd is None:
@@ -2227,35 +2467,35 @@
   if pfd is None:
     pfd = "0"
   #post join delay
-  map['pjd'] = pjd
+  clumap['pjd'] = pjd
   #post fail delay
-  map['pfd'] = pfd
+  clumap['pfd'] = pfd
   #-------------
   #if multicast
   multicast_url = prop_baseurl + PROPERTIES_TAB + "=" + PROP_MCAST_TAB
-  map['multicast_url'] = multicast_url
+  clumap['multicast_url'] = multicast_url
   #mcast addr
   is_mcast = model.isMulticast()
-  #map['is_mcast'] = is_mcast
+  #clumap['is_mcast'] = is_mcast
   if is_mcast:
-    map['mcast_addr'] = model.getMcastAddr()
-    map['is_mcast'] = "True"
+    clumap['mcast_addr'] = model.getMcastAddr()
+    clumap['is_mcast'] = "True"
   else:
-    map['is_mcast'] = "False"
-    map['mcast_addr'] = "1.2.3.4"
+    clumap['is_mcast'] = "False"
+    clumap['mcast_addr'] = "1.2.3.4"
 
   #-------------
   #quorum disk params
   quorumd_url = prop_baseurl + PROPERTIES_TAB + "=" + PROP_QDISK_TAB
-  map['quorumd_url'] = quorumd_url
+  clumap['quorumd_url'] = quorumd_url
   is_quorumd = model.isQuorumd()
-  map['is_quorumd'] = is_quorumd
-  map['interval'] = ""
-  map['tko'] = ""
-  map['votes'] = ""
-  map['min_score'] = ""
-  map['device'] = ""
-  map['label'] = ""
+  clumap['is_quorumd'] = is_quorumd
+  clumap['interval'] = ""
+  clumap['tko'] = ""
+  clumap['votes'] = ""
+  clumap['min_score'] = ""
+  clumap['device'] = ""
+  clumap['label'] = ""
 
   #list struct for heuristics...
   hlist = list()
@@ -2264,27 +2504,27 @@
     qdp = model.getQuorumdPtr()
     interval = qdp.getAttribute('interval')
     if interval is not None:
-      map['interval'] = interval
+      clumap['interval'] = interval
 
     tko = qdp.getAttribute('tko')
     if tko is not None:
-      map['tko'] = tko
+      clumap['tko'] = tko
 
     votes = qdp.getAttribute('votes')
     if votes is not None:
-      map['votes'] = votes
+      clumap['votes'] = votes
 
     min_score = qdp.getAttribute('min_score')
     if min_score is not None:
-      map['min_score'] = min_score
+      clumap['min_score'] = min_score
 
     device = qdp.getAttribute('device')
     if device is not None:
-      map['device'] = device
+      clumap['device'] = device
 
     label = qdp.getAttribute('label')
     if label is not None:
-      map['label'] = label
+      clumap['label'] = label
 
     heuristic_kids = qdp.getChildren()
     h_ctr = 0
@@ -2313,9 +2553,9 @@
       else:
         hmap['hinterval'] = ""
       hlist.append(hmap)
-  map['hlist'] = hlist
+  clumap['hlist'] = hlist
 
-  return map
+  return clumap
 
 def getClustersInfo(self, status, req):
   map = {}
@@ -2335,6 +2575,10 @@
   if len(clulist) < 1:
     return {}
   clu = clulist[0]
+  cluerror = False
+  if 'error' in clu:
+    cluerror = True
+    map['error'] = True
   clustername = clu['name']
   if clu['alias'] != "":
     map['clusteralias'] = clu['alias']
@@ -2349,6 +2593,7 @@
     map['running'] = "false"
   map['votes'] = clu['votes']
   map['minquorum'] = clu['minQuorum']
+
   map['clucfg'] = baseurl + "?" + PAGETYPE + "=" + CLUSTER_CONFIG + "&" + CLUNAME + "=" + clustername
 
   map['restart_url'] = baseurl + "?" + PAGETYPE + "=" + CLUSTER_PROCESS + "&" + CLUNAME + "=" + clustername + '&task=' + CLUSTER_RESTART
@@ -2370,6 +2615,7 @@
   map['currentservices'] = svc_dict_list
   node_dict_list = list()
   for item in nodelist:
+    node_error = 'error' in item
     nmap = {}
     name = item['name']
     nmap['nodename'] = name
@@ -2872,15 +3118,16 @@
 
   infohash['currentservices'] = svc_dict_list
 
-  #next is faildoms
-  fdoms = model.getFailoverDomainsForNode(nodename)
   fdom_dict_list = list()
-  for fdom in fdoms:
-    fdom_dict = {}
-    fdom_dict['name'] = fdom.getName()
-    fdomurl = baseurl + "?" + PAGETYPE + "=" + FDOM_CONFIG + "&" + CLUNAME + "=" + clustername + "&fdomname=" + fdom.getName()
-    fdom_dict['fdomurl'] = fdomurl
-    fdom_dict_list.append(fdom_dict)
+  if model:
+    #next is faildoms
+    fdoms = model.getFailoverDomainsForNode(nodename)
+    for fdom in fdoms:
+      fdom_dict = {}
+      fdom_dict['name'] = fdom.getName()
+      fdomurl = baseurl + "?" + PAGETYPE + "=" + FDOM_CONFIG + "&" + CLUNAME + "=" + clustername + "&fdomname=" + fdom.getName()
+      fdom_dict['fdomurl'] = fdomurl
+      fdom_dict_list.append(fdom_dict)
 
   infohash['fdoms'] = fdom_dict_list
 
@@ -2911,7 +3158,6 @@
 
   infohash['logurl'] = '/luci/logs/?nodename=' + nodename_resolved + '&clustername=' + clustername
   return infohash
-  #get list of faildoms for node
 
 def getNodesInfo(self, model, status, req):
   resultlist = list()
@@ -3015,6 +3261,10 @@
   return resultlist
 
 def getFence(self, model, request):
+  if not model:
+    luci_log.debug_verbose('getFence0: model is None')
+    return {}
+
   map = {}
   fencename = request['fencename']
   fencedevs = model.getFenceDevices()
@@ -3061,6 +3311,10 @@
   raise
   
 def getFenceInfo(self, model, request):
+  if not model:
+    luci_log.debug_verbose('getFenceInfo00: model is None')
+    return {}
+
   try:
     clustername = request['clustername']
   except:
@@ -3311,9 +3565,14 @@
   return map    
       
 def getFencesInfo(self, model, request):
+  map = {}
+  if not model:
+    luci_log.debug_verbose('getFencesInfo0: model is None')
+    map['fencedevs'] = list()
+    return map
+
   clustername = request['clustername']
   baseurl = request['URL']
-  map = {}
   fencedevs = list() #This is for the fencedev list page
 
   #Get list of fence devices
@@ -3798,6 +4057,7 @@
 	for item in modelb.getResources():
 		itemmap = {}
 		itemmap['name'] = item.getName()
+		itemmap['attrs'] = item.attr_hash
 		itemmap['type'] = item.resource_type
 		itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&resourcename=" + item.getName() + "&pagetype=" + RESOURCE_CONFIG
 		itemmap['url'] = baseurl + "?" + "clustername=" + cluname + "&resourcename=" + item.getName() + "&pagetype=" + RESOURCE
@@ -3859,6 +4119,82 @@
 			except:
 				continue
 
+def delService(self, request):
+	errstr = 'An error occurred while attempting to set the new cluster.conf'
+
+	try:
+		modelb = request.SESSION.get('model')
+	except Exception, e:
+		luci_log.debug_verbose('delService0: no model: %s' % str(e))
+		return (False, {'errors': [ errstr ] })
+
+	name = None
+	try:
+		name = request['servicename']
+	except:
+		try:
+			name = request.form['servicename']
+		except:
+			pass
+
+	if name is None:
+		luci_log.debug_verbose('delService1: no service name')
+		return (False, {'errors': [ '%s: no service name was provided.' % errstr ]})
+
+	clustername = None
+	try:
+		clustername = request['clustername']
+	except:
+		try:
+			clustername = request.form['clustername']
+		except:
+			pass
+
+	if clustername is None:
+		luci_log.debug_verbose('delService2: no cluster name for %s' % name)
+		return (False, {'errors': [ '%s: no cluster name was provided.' % errstr ]})
+
+	rc = getRicciAgent(self, clustername)
+	if not rc:
+		luci_log.debug_verbose('delService3: unable to get ricci agent for cluster %s' % clustername)
+		return (False, {'errors': [ '%s: unable to find a Ricci agent for this cluster.' % errstr ]})
+
+	try:
+		ragent = rc.hostname()
+		if not ragent:
+			raise Exception, 'unable to determine the hostname of the ricci agent'
+	except Exception, e:
+		luci_log.debug_verbose('delService4: %s: %s' % (errstr, str(e)))
+		return (False, {'errors': [ '%s: unable to find a Ricci agent for this cluster.' % errstr ]})
+
+	try:
+		modelb.deleteService(name)
+	except Exception, e:
+		luci_log.debug_verbose('delService5: Unable to find a service named %s for cluster %s' % (name, clustername))
+		return (False, {'errors': [ '%s: error removing service %s.' % (errstr, name) ]})
+
+	try:
+		conf = modelb.exportModelAsString()
+		if not conf:
+			raise Exception, 'model string is blank'
+	except Exception, e:
+		luci_log.debug_verbose('delService6: exportModelAsString failed: %s' \
+			% str(e))
+		return (False, {'errors': [ '%s: error removing service %s.' % (errstr, name) ]})
+
+	batch_number, result = setClusterConf(rc, str(conf))
+	if batch_number is None or result is None:
+		luci_log.debug_verbose('delService7: missing batch and/or result')
+		return (False, {'errors': [ '%s: error removing service %s.' % (errstr, name) ]})
+
+	try:
+		set_node_flag(self, clustername, ragent, str(batch_number), SERVICE_DELETE, "Removing service \'%s\'" % name)
+	except Exception, e:
+		luci_log.debug_verbose('delService8: failed to set flags: %s' % str(e))
+
+	response = request.RESPONSE
+	response.redirect(request['URL'] + "?pagetype=" + SERVICES + "&clustername=" + clustername + '&busyfirst=true')
+
 def delResource(self, rc, request):
 	errstr = 'An error occurred while attempting to set the new cluster.conf'
 
@@ -4516,7 +4852,7 @@
 	'gfs': addGfs,
 	'nfsm': addNfsm,
 	'nfsx': addNfsx,
-	'nfsc': addNfsx,
+	'nfsc': addNfsc,
 	'scr': addScr,
 	'smb': addSmb
 }
@@ -4651,6 +4987,17 @@
 	response = request.RESPONSE
 	response.redirect(request['URL'] + "?pagetype=" + RESOURCES + "&clustername=" + clustername + '&busyfirst=true')
 
+def getResource(modelb, name):
+	resPtr = modelb.getResourcesPtr()
+	resources = resPtr.getChildren()
+
+	for res in resources:
+		if res.getName() == name:
+			return res
+
+	luci_log.debug_verbose('getResource: unable to find resource \"%s\"' % name)
+	raise KeyError, name
+
 def getResourceForEdit(modelb, name):
 	resPtr = modelb.getResourcesPtr()
 	resources = resPtr.getChildren()
@@ -4660,7 +5007,7 @@
 			resPtr.removeChild(res)
 			return res
 
-	luci_log.debug_verbose('unable to find resource \"%s\"' % name)
+	luci_log.debug_verbose('GRFE0: unable to find resource \"%s\"' % name)
 	raise KeyError, name
 
 def appendModel(request, model):
--- conga/luci/site/luci/Extensions/conga_constants.py	2006/11/16 19:34:53	1.19.2.2
+++ conga/luci/site/luci/Extensions/conga_constants.py	2006/12/07 17:54:31	1.19.2.3
@@ -43,6 +43,7 @@
 FENCEDEV_CONFIG="53"
 FENCEDEV="54"
 CLUSTER_DAEMON="55"
+SERVICE_DELETE = '56'
 
 #Cluster tasks
 CLUSTER_STOP = '1000'
@@ -119,7 +120,7 @@
 PRE_JOIN = "Packages are installed and configuration has been distributed, but the node has not yet joined the cluster."
 
 
-POSSIBLE_REBOOT_MESSAGE = "This node is not currently responding and is probably<br/>rebooting as planned. This state should persist for 5 minutes or so..."
+POSSIBLE_REBOOT_MESSAGE = "This node is not currently responding and is probably rebooting as planned. This state should persist for 5 minutes or so..."
 
 REDIRECT_MSG = " You will be redirected in 5 seconds. Please fasten your safety restraints."
 
--- conga/luci/site/luci/Extensions/ricci_bridge.py	2006/11/20 23:36:12	1.30.2.10
+++ conga/luci/site/luci/Extensions/ricci_bridge.py	2006/12/07 17:54:31	1.30.2.11
@@ -63,7 +63,7 @@
 	batch += '</function_call>'
 	batch += '</request>'
 	batch += '</module>'
-		
+
 	need_reboot = install_base or install_services or install_shared_storage or install_LVS
 	if need_reboot:
 		batch += '<module name="service">'
@@ -96,7 +96,7 @@
 		batch += '<function_call name="install"/>'
 		batch += '</request>'
 		batch += '</module>'
-		
+
 	batch += '<module name="cluster">'
 	batch += '<request API_version="1.0">'
 	batch += '<function_call name="set_cluster.conf">'
@@ -236,7 +236,7 @@
 		batch += '<cman expected_votes="1" two_node="1"/>'
 	else:
 		batch += '<cman/>'
- 
+
 	batch += '<fencedevices/>'
 	batch += '<rm/>'
 	batch += '</cluster>'
@@ -298,66 +298,39 @@
 		pass
 
 	return (None, None)
-	
 
-def getPayload(bt_node):
-	if not bt_node:
-		return None
-
-	mod_node = None
-	for node in bt_node.childNodes:
-		if node.nodeType == xml.dom.Node.ELEMENT_NODE and node.nodeName == 'module':
-			mod_node = node
-	if not mod_node:
-		return None
-
-	resp_node = None
-	for node in mod_node.childNodes:
-		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-			resp_node = node
-	if not resp_node:
-		return None
+def getClusterStatusBatch(rc):
+	batch_str = '<module name="cluster"><request API_version="1.0"><function_call name="status"/></request></module>'
+	ricci_xml = rc.batch_run(batch_str, async=False)
 
-	fr_node = None
-	for node in resp_node.childNodes:
-		if node.nodeType == xml.dom.Node.ELEMENT_NODE:
-			fr_node = node
-	if not fr_node:
+	try:
+		cluster_tags = ricci_xml.getElementsByTagName('cluster')
+	except Exception, e:
+		luci_log.debug_verbose('getClusterStatusBatch0: %s' % str(e))
 		return None
 
-	varnode = None
-	for node in fr_node.childNodes:
-		if node.nodeName == 'var':
-			varnode = node
-			break
-	if not varnode:
-		return None
+	if len(cluster_tags) < 1:
+		luci_log.debug_verbose('getClusterStatusBatch1: %d entries - expecting 1' \
+			% len(cluster_tags))
+	elif len(cluster_tags) > 1:
+		luci_log.debug_verbose('getClusterStatusBatch2: %d entries - expecting 1, using the first' % len(cluster_tags))
 
-	cl_node = None
-	for node in varnode.childNodes:
-		if node.nodeName == 'cluster':
-			cl_node = node
-			break
-	if not cl_node:
+	try:
+		cluster_node = cluster_tags[0]
+		if not cluster_node:
+			raise Exception, 'element 0 is None'
+	except Exception, e:
+		luci_log.debug_verbose('getClusterStatusBatch3: %s' % str(e))
 		return None
 
-	doc = minidom.Document()
-	doc.appendChild(cl_node)
-	return doc
-
-def getClusterStatusBatch(rc):
-	batch_str = '<module name="cluster"><request API_version="1.0"><function_call name="status"/></request></module>'
-	ricci_xml = rc.batch_run(batch_str, async=False)
-
-	if not ricci_xml or not ricci_xml.firstChild:
-		luci_log.debug_verbose('ricci_xml is None from batch_run')
-		
-	doc = getPayload(ricci_xml.firstChild)
-	if not doc or not doc.firstChild:
-		luci_log.debug_verbose('doc is None from getPayload: %s' % ricci_xml.toxml())
-		return None
+	try:
+		doc = minidom.Document()
+		doc.appendChild(cluster_node)
+		return doc
+	except Exception, e:
+		luci_log.debug_verbose('getClusterStatusBatch4: %s' % str(e))
 
-	return doc
+	return None
 
 def setClusterConf(rc, clusterconf, propagate=True):
 	if propagate == True:
@@ -490,7 +463,7 @@
 		return None, None
 	ricci_xml = rc.batch_run(batch)
 	return batchAttemptResult(ricci_xml)
-	
+
 def restartService(rc, servicename):
 	batch_str = '<module name="cluster"><request API_version="1.0"><function_call name="restart_service"><var mutable="false" name="servicename" type="string" value=\"' + servicename + '\"/></function_call></request></module>'
 



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2006-12-06 18:38 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2006-12-06 18:38 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe at sourceware.org	2006-12-06 18:38:55

Modified files:
	luci/cluster   : form-chooser form-macros 
	luci/site/luci/Extensions: cluster_adapters.py 
	                           conga_constants.py 

Log message:
	The service delete option was doing nothing. Make it work, but only when the service is not running.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&r1=1.13&r2=1.14
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&r1=1.121&r2=1.122
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.172&r2=1.173
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&r1=1.27&r2=1.28

--- conga/luci/cluster/form-chooser	2006/11/10 19:44:57	1.13
+++ conga/luci/cluster/form-chooser	2006/12/06 18:38:53	1.14
@@ -80,6 +80,9 @@
     <span tal:omit-tag="" tal:condition="python: ptype == '25'">
      <div metal:use-macro="here/form-macros/macros/serviceprocess-form"/>
     </span>
+	<tal:block tal:condition="python: ptype == '56'">
+		<div metal:use-macro="here/form-macros/macros/servicedelete-form" />
+	</tal:block>
     <span tal:omit-tag="" tal:condition="python: ptype == '26'">
      <div metal:use-macro="here/form-macros/macros/servicestart"/>
     </span>
--- conga/luci/cluster/form-macros	2006/12/05 23:32:34	1.121
+++ conga/luci/cluster/form-macros	2006/12/06 18:38:54	1.122
@@ -2775,9 +2775,31 @@
 					<form method="post" onSubmit="return dropdown(this.gourl)">
 						<select name="gourl">
 							<option value="">Choose a Task...</option>
-							<option value="" tal:attributes="value svc/cfgurl">Configure</option>
+							<option
+								tal:attributes="value svc/cfgurl | nothing"
+								tal:content="string:Configure this service" />
+
 							<option value="">----------</option>
-							<option value="">Delete</option>
+
+							<option
+								tal:condition="running"
+								tal:attributes="value svc/retstarturl| nothing"
+								tal:content="string:Restart this service" />
+
+							<option
+								tal:condition="running"
+								tal:attributes="value svc/disableurl | nothing"
+								tal:content="string:Stop this service" />
+
+							<option
+								tal:condition="not: running"
+								tal:attributes="value svc/enableurl | nothing"
+								tal:content="string:Start this service" />
+
+							<option
+								tal:condition="not: running"
+								tal:attributes="value svc/delurl | nothing"
+								tal:content="string:Delete this service" />
 						</select>
 						<input type="submit" value="Go"/>
 					</form>
@@ -3047,14 +3069,15 @@
 							<option value="" tal:attributes="value innermap/disableurl">Disable this service</option>
 							<option value="">----------</option>
 							<option tal:repeat="starturl innermap/links" value="" tal:attributes="value starturl/url">Start this service on <span tal:replace="starturl/nodename"/></option>
-							<option value="">----------</option>
-							<option value="">Delete this service</option>
 						</tal:block>
 
 						<tal:block tal:condition="not: running">
 							<option value="">----------</option>
 							<option value="" tal:attributes="value innermap/enableurl">Enable this service</option>
 							<option value="">----------</option>
+							<option
+								tal:attributes="value innermap/delurl | nothing"
+								tal:content="string:Delete this service" />
 						</tal:block>
 					</select>
 					<input type="submit" value="Go"/>
@@ -3152,6 +3175,11 @@
 	<h2>Service Process Form</h2>
 </div>
 
+<div metal:define-macro="servicedelete-form">
+	<h2>Service Delete Form</h2>
+	<tal:block tal:define="dummy python: here.delService(request)" />
+</div>
+
 <div metal:define-macro="resources-form">
 	<h2>Resources Form</h2>
 </div>
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2006/12/05 23:32:35	1.172
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2006/12/06 18:38:54	1.173
@@ -404,7 +404,6 @@
 		form_xml = request['form_xml']
 		if not form_xml:
 			raise KeyError, 'form_xml must not be blank'
-		luci_log.debug_verbose('VSAXML DUMP: %s' % form_xml)
 	except Exception, e:
 		luci_log.debug_verbose('vSA0: no form_xml: %s' % str(e))
 		return (False, {'errors': ['No resource data was supplied for this service.']})
@@ -1920,6 +1919,7 @@
 				itemmap['nodename'] = item['nodename']
 			itemmap['autostart'] = item['autostart']
 			itemmap['cfgurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + SERVICE
+			itemmap['delurl'] = baseurl + "?" + "clustername=" + cluname + "&servicename=" + item['name'] + "&pagetype=" + SERVICE_DELETE
 
 			svc = modelb.retrieveServiceByName(item['name'])
 			dom = svc.getAttribute("domain")
@@ -1980,6 +1980,8 @@
 					innermap['current'] = "This service is currently running on %s" % nodename
 					innermap['disableurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_STOP
 					innermap['restarturl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_RESTART
+					innermap['delurl'] = baseurl + "?" + "clustername=" + cluname +"&servicename=" + servicename + "&pagetype=" + SERVICE_DELETE
+
 					nodes = modelb.getNodes()
 					for node in nodes:
 						starturl = {}
@@ -2026,16 +2028,18 @@
 	if parent is not None:
 		rc_map['parent'] = parent
 	rc_map['name'] = child.getName()
+
+	#Note: Final version needs all resource attrs
 	if child.isRefObject() == True:
 		rc_map['ref_object'] = True
 		rc_map['type'] = child.getObj().getResourceType()
+		rc_map['attrs'] = child.getObj().getAttributes()
 	else:
 		rc_map['type'] = child.getResourceType()
+		rc_map['attrs'] = child.getAttributes()
 
 	rc_map['indent_ctr'] = indent_ctr
 
-	#Note: Final version needs all resource attrs
-	rc_map['attrs'] = child.getAttributes()
 	rc_map['uuid'] = make_uuid('resource')
 	rc_map['parent_uuid'] = parent_uuid
 
@@ -3985,6 +3989,82 @@
 			except:
 				continue
 
+def delService(self, request):
+	errstr = 'An error occurred while attempting to set the new cluster.conf'
+
+	try:
+		modelb = request.SESSION.get('model')
+	except Exception, e:
+		luci_log.debug_verbose('delService0: no model: %s' % str(e))
+		return (False, {'errors': [ errstr ] })
+
+	name = None
+	try:
+		name = request['servicename']
+	except:
+		try:
+			name = request.form['servicename']
+		except:
+			pass
+
+	if name is None:
+		luci_log.debug_verbose('delService1: no service name')
+		return (False, {'errors': [ '%s: no service name was provided.' % errstr ]})
+
+	clustername = None
+	try:
+		clustername = request['clustername']
+	except:
+		try:
+			clustername = request.form['clustername']
+		except:
+			pass
+
+	if clustername is None:
+		luci_log.debug_verbose('delService2: no cluster name for %s' % name)
+		return (False, {'errors': [ '%s: no cluster name was provided.' % errstr ]})
+
+	rc = getRicciAgent(self, clustername)
+	if not rc:
+		luci_log.debug_verbose('delService3: unable to get ricci agent for cluster %s' % clustername)
+		return (False, {'errors': [ '%s: unable to find a Ricci agent for this cluster.' % errstr ]})
+
+	try:
+		ragent = rc.hostname()
+		if not ragent:
+			raise Exception, 'unable to determine the hostname of the ricci agent'
+	except Exception, e:
+		luci_log.debug_verbose('delService4: %s: %s' % (errstr, str(e)))
+		return (False, {'errors': [ '%s: unable to find a Ricci agent for this cluster.' % errstr ]})
+
+	try:
+		modelb.deleteService(name)
+	except Exception, e:
+		luci_log.debug_verbose('delService5: Unable to find a service named %s for cluster %s' % (name, clustername))
+		return (False, {'errors': [ '%s: error removing service %s.' % (errstr, name) ]})
+
+	try:
+		conf = modelb.exportModelAsString()
+		if not conf:
+			raise Exception, 'model string is blank'
+	except Exception, e:
+		luci_log.debug_verbose('delService6: exportModelAsString failed: %s' \
+			% str(e))
+		return (False, {'errors': [ '%s: error removing service %s.' % (errstr, name) ]})
+
+	batch_number, result = setClusterConf(rc, str(conf))
+	if batch_number is None or result is None:
+		luci_log.debug_verbose('delService7: missing batch and/or result')
+		return (False, {'errors': [ '%s: error removing service %s.' % (errstr, name) ]})
+
+	try:
+		set_node_flag(self, clustername, ragent, str(batch_number), SERVICE_DELETE, "Removing service \'%s\'" % name)
+	except Exception, e:
+		luci_log.debug_verbose('delService8: failed to set flags: %s' % str(e))
+
+	response = request.RESPONSE
+	response.redirect(request['URL'] + "?pagetype=" + SERVICES + "&clustername=" + clustername + '&busyfirst=true')
+
 def delResource(self, rc, request):
 	errstr = 'An error occurred while attempting to set the new cluster.conf'
 
@@ -4068,9 +4148,6 @@
 	if form is None:
 		form = request.form
 
-	if form is not None:
-		luci_log.debug_verbose('addIp DUMP: %s' % str(form.items()))
-
 	if not form:
 		luci_log.debug_verbose('addIp error: form is missing')
 		return None
--- conga/luci/site/luci/Extensions/conga_constants.py	2006/11/27 20:06:53	1.27
+++ conga/luci/site/luci/Extensions/conga_constants.py	2006/12/06 18:38:55	1.28
@@ -43,6 +43,7 @@
 FENCEDEV_CONFIG="53"
 FENCEDEV="54"
 CLUSTER_DAEMON="55"
+SERVICE_DELETE = '56'
 
 #Cluster tasks
 CLUSTER_STOP = '1000'



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2006-11-10 19:44 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2006-11-10 19:44 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe at sourceware.org	2006-11-10 19:44:57

Modified files:
	luci/cluster   : form-chooser form-macros portlet_cluconfig 
	                 resource-form-macros resource_form_handlers.js 
	luci/site/luci/Extensions: cluster_adapters.py 

Log message:
	- fix the redirection upon completion of async ricci tasks
	- fix a bug that caused adding nfs mount resources to fail

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&r1=1.12&r2=1.13
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&r1=1.102&r2=1.103
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/portlet_cluconfig.diff?cvsroot=cluster&r1=1.2&r2=1.3
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/resource-form-macros.diff?cvsroot=cluster&r1=1.23&r2=1.24
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/resource_form_handlers.js.diff?cvsroot=cluster&r1=1.21&r2=1.22
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.160&r2=1.161

--- conga/luci/cluster/form-chooser	2006/10/16 20:25:33	1.12
+++ conga/luci/cluster/form-chooser	2006/11/10 19:44:57	1.13
@@ -12,7 +12,7 @@
   <span tal:condition="not: busywaiting">
     <span tal:omit-tag="" tal:define="global ptype request/pagetype |nothing"/>
     <span tal:omit-tag="" tal:condition="python: not ptype">
-     <div metal:use-macro="here/form-macros/macros/entry-form"/>
+     <div metal:use-macro="here/form-macros/macros/clusters-form"/>
     </span>
     <span tal:omit-tag="" tal:condition="python: ptype == '0' or ptype == '1' or ptype == '2' or ptype == '3'">
      <div metal:use-macro="here/form-macros/macros/clusters-form"/>
--- conga/luci/cluster/form-macros	2006/11/09 20:32:02	1.102
+++ conga/luci/cluster/form-macros	2006/11/10 19:44:57	1.103
@@ -7,7 +7,6 @@
 <body>
 
 <div metal:define-macro="entry-form">
-	<h2>Entry Form</h2>
 </div>
 
 <div metal:define-macro="busywaitpage">
--- conga/luci/cluster/portlet_cluconfig	2006/09/27 22:24:11	1.2
+++ conga/luci/cluster/portlet_cluconfig	2006/11/10 19:44:57	1.3
@@ -10,7 +10,7 @@
 
 <dl class="portlet" id="portlet-cluconfig-tree">
     <dt class="portletHeader">
-        <a href="#">
+        <a href="/luci/cluster/index_html?pagetype=3">
           Clusters
         </a>
     </dt>
@@ -36,7 +36,8 @@
 
 <dl class="portlet" id="portlet-cluconfig-tree">
     <dt class="portletHeader">
-        <a href="#" tal:attributes="href python:here.getClusterURL(request,modelb)">
+        <a href="/luci/cluster/index_html?pagetype=3"
+			tal:attributes="href python:here.getClusterURL(request,modelb)">
           <div tal:omit-tag="" tal:content="python: here.getClusterAlias(modelb)" />
         </a>
     </dt>
--- conga/luci/cluster/resource-form-macros	2006/11/07 21:33:52	1.23
+++ conga/luci/cluster/resource-form-macros	2006/11/10 19:44:57	1.24
@@ -684,14 +684,12 @@
 				<input type="radio" name="nfstype" value="nfs"
 					tal:attributes="
 						disabled python: editDisabled;
-						content string: NFS (version 3);
-						checked python: nfstype == 'nfs' and 'checked'" />
+						checked python: nfstype != 'nfs4' and 'checked'" />NFS3
 				<br/>
 				<input type="radio" name="nfstype" value="nfs4"
 					tal:attributes="
 						disabled python: editDisabled;
-						content string: NFS4;
-						checked python: nfstype == 'nfs4' and 'checked'" />
+						checked python: nfstype == 'nfs4' and 'checked'" />NFS4
 			</td>
 		</tr>
 
--- conga/luci/cluster/resource_form_handlers.js	2006/10/30 21:21:16	1.21
+++ conga/luci/cluster/resource_form_handlers.js	2006/11/10 19:44:57	1.22
@@ -101,7 +101,7 @@
 function validate_nfs_mount(form) {
 	var errors = new Array();
 
-	if (!form.mountpoint || str_is_blank(form.mounpoint.value)) {
+	if (!form.mountpoint || str_is_blank(form.mountpoint.value)) {
 		errors.push('No mount point was given.');
 		set_form_err(form.mountpoint);
 	} else
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2006/11/10 18:18:09	1.160
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2006/11/10 19:44:57	1.161
@@ -901,13 +901,13 @@
   cname = None
   try:
     cname = request[CLUNAME]
-  except KeyError, e:
+  except:
     cname = ""
 
   try:
     url = request['URL']
-  except KeyError, e:
-    url = "."
+  except:
+    url = "/luci/cluster/index_html"
 
   try:
     pagetype = request[PAGETYPE]
@@ -998,13 +998,13 @@
   #There should be a positive page type
   try:
     pagetype = request[PAGETYPE]
-  except KeyError, e:
+  except:
     pagetype = '3'
 
   try:
     url = request['URL']
   except KeyError, e:
-    url = "."
+    url = "/luci/cluster/index_html"
 
   #The only way this method can run is if there exists
   #a clustername query var
@@ -1444,7 +1444,7 @@
     else:
       selectedtab = "homebase"
   except KeyError, e:
-    pass
+    selectedtab = None
 
   htab = { 'Title':"homebase",
            'Description':"Home base for this luci server",
@@ -1457,7 +1457,7 @@
 
   ctab = { 'Title':"cluster",
            'Description':"Cluster configuration page",
-           'Taburl':"/luci/cluster?pagetype=3"}
+           'Taburl':"/luci/cluster/index_html?pagetype=3"}
   if selectedtab == "cluster":
     ctab['isSelected'] = True
   else:
@@ -1633,18 +1633,18 @@
 		baseurl = req['URL']
 		if not baseurl:
 			raise KeyError, 'is blank'
-	except KeyError, e:
-		baseurl = '.'
+	except:
+		baseurl = '/luci/cluster/index_html'
 
 	try:
 		cluname = req['clustername']
 		if not cluname:
 			raise KeyError, 'is blank'
-	except KeyError, e:
+	except:
 		try:
 			cluname = req.form['clusterName']
 			if not cluname:
-				raise
+				raise KeyError, 'is blank'
 		except:
 			cluname = '[error retrieving cluster name]'
 
@@ -1678,8 +1678,8 @@
 		baseurl = req['URL']
 		if not baseurl:
 			raise KeyError, 'is blank'
-	except KeyError, e:
-		baseurl = '.'
+	except:
+		baseurl = '/luci/cluster/index_html'
 
 	try:
 		cluname = req['clustername']
@@ -1835,7 +1835,7 @@
 		luci_log.debug_verbose('startService4: error setting flags for service %s at node %s for cluster %s' % (svcname, nodename, cluname))
 
 	response = req.RESPONSE
-	response.redirect(req['HTTP_REFERER'] + "&busyfirst=true")
+	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
 
 def serviceRestart(self, rc, req):
 	svcname = None
@@ -1875,7 +1875,7 @@
 		luci_log.debug_verbose('serviceRestart3: error setting flags for service %s for cluster %s' % (svcname, cluname))
 
 	response = req.RESPONSE
-	response.redirect(req['HTTP_REFERER'] + "&busyfirst=true")
+	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
 
 def serviceStop(self, rc, req):
 	svcname = None
@@ -1915,7 +1915,7 @@
 		luci_log.debug_verbose('serviceStop3: error setting flags for service %s for cluster %s' % (svcname, cluname))
 
 	response = req.RESPONSE
-	response.redirect(req['HTTP_REFERER'] + "&busyfirst=true")
+	response.redirect(req['URL'] + "?pagetype=" + SERVICE_LIST + "&clustername=" + cluname + '&busyfirst=true')
 
 def getFdomsInfo(self, modelb, request, clustatus):
   slist = list()
@@ -2031,7 +2031,7 @@
 
 	response = request.RESPONSE
 	response.redirect('%s?pagetype=%s&clustername=%s&busyfirst=true' \
-		 % (request['URL'], CLUSTER, model.getClusterName()))
+		 % (request['URL'], NODES, model.getClusterName()))
 
 def getClusterInfo(self, model, req):
   try:
@@ -2638,39 +2638,35 @@
 			luci_log.debug_verbose('NTP: nodeLeave failed')
 			return None
 
-		#Is this correct? Should we re-direct to the cluster page?
 		response = request.RESPONSE
-		response.redirect(request['URL'] + "?pagetype=" + CLUSTER_CONFIG + "&clustername=" + clustername)
+		response.redirect(request['URL'] + "?pagetype=" + NODE_LIST + "&clustername=" + clustername + '&busyfirst=true')
 	elif task == NODE_JOIN_CLUSTER:
 		if nodeJoin(self, rc, clustername, nodename_resolved) is None:
 			luci_log.debug_verbose('NTP: nodeJoin failed')
 			return None
 
-		#Once again, is this correct? Should we re-direct to the cluster page?
 		response = request.RESPONSE
-		response.redirect(request['URL'] + "?pagetype=" + CLUSTER_CONFIG + "&clustername=" + clustername)
+		response.redirect(request['URL'] + "?pagetype=" + NODE_LIST + "&clustername=" + clustername + '&busyfirst=true')
 	elif task == NODE_REBOOT:
 		if forceNodeReboot(self, rc, clustername, nodename_resolved) is None:
 			luci_log.debug_verbose('NTP: nodeReboot failed')
 			return None
 
-		#Once again, is this correct? Should we re-direct to the cluster page?
 		response = request.RESPONSE
-		response.redirect(request['URL'] + "?pagetype=" + CLUSTER_CONFIG + "&clustername=" + clustername)
+		response.redirect(request['URL'] + "?pagetype=" + NODE_LIST + "&clustername=" + clustername + '&busyfirst=true')
 	elif task == NODE_FENCE:
 		if forceNodeFence(self, clustername, nodename, nodename_resolved) is None:
 			luci_log.debug_verbose('NTP: nodeFencefailed')
 			return None
 
-		#Once again, is this correct? Should we re-direct to the cluster page?
 		response = request.RESPONSE
-		response.redirect(request['URL'] + "?pagetype=" + CLUSTER_CONFIG + "&clustername=" + clustername)
+		response.redirect(request['URL'] + "?pagetype=" + NODE_LIST + "&clustername=" + clustername + '&busyfirst=true')
 	elif task == NODE_DELETE:
 		if nodeDelete(self, rc, model, clustername, nodename, nodename_resolved) is None:
 			luci_log.debug_verbose('NTP: nodeDelete failed')
 			return None
 		response = request.RESPONSE
-		response.redirect(request['HTTP_REFERER'] + "&busyfirst=true")
+		response.redirect(request['URL'] + "?pagetype=" + NODE_LIST + "&clustername=" + clustername + '&busyfirst=true')
 
 def getNodeInfo(self, model, status, request):
   infohash = {}
@@ -3360,7 +3356,7 @@
     luci_log.debug('ICB5: An error occurred while looking for cluster %s flags at path %s' % (cluname, path))
     return map
 
-  luci_log.debug_verbose('ICB6: isClusterBusy: %s is busy: %d flags' \
+  luci_log.debug_verbose('ICB6: %s is busy: %d flags' \
       % (cluname, len(items)))
   map['busy'] = "true"
   #Ok, here is what is going on...if there is an item,
@@ -3541,7 +3537,7 @@
         try:
             clusterfolder.manage_delObjects(item[0])
         except Exception, e:
-            luci_log.info('Unable to delete %s: %s' % (item[0], str(e)))
+            luci_log.info('ICB16: Unable to delete %s: %s' % (item[0], str(e)))
       else:
         node_report = {}
         map['busy'] = "true"
@@ -3563,7 +3559,12 @@
     map['refreshurl'] = "5; url=" + wholeurl
     req['specialpagetype'] = "1"
   else:
-    map['refreshurl'] = '5; url=\".\"'
+    try:
+      query = req['QUERY_STRING'].replace('&busyfirst=true', '')
+      map['refreshurl'] = '5; url=' + req['ACTUAL_URL'] + '?' + query
+    except:
+      map['refreshurl'] = '5; url=/luci/cluster?pagetype=3'
+  luci_log.debug_verbose('ICB17: refreshurl is \"%s\"' % map['refreshurl'])
   return map
 
 def getClusterOS(self, rc):
@@ -3739,7 +3740,7 @@
 		luci_log.debug_verbose('delResource7: failed to set flags: %s' % str(e))
 
 	response = request.RESPONSE
-	response.redirect(request['HTTP_REFERER'] + "&busyfirst=true")
+	response.redirect(request['URL'] + "?pagetype=" + RESOURCES + "&clustername=" + clustername + '&busyfirst=true')
 
 def addIp(request, form=None):
 	if form is None:
@@ -4452,7 +4453,7 @@
 		luci_log.debug_verbose('addResource7: failed to set flags: %s' % str(e))
 
 	response = request.RESPONSE
-	response.redirect(request['HTTP_REFERER'] + "&busyfirst=true")
+	response.redirect(request['URL'] + "?pagetype=" + RESOURCES + "&clustername=" + clustername + '&busyfirst=true')
 
 def getResourceForEdit(modelb, name):
 	resPtr = modelb.getResourcesPtr()



^ permalink raw reply	[flat|nested] 10+ messages in thread
* [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m ...
@ 2006-10-09 17:12 rmccabe
  0 siblings, 0 replies; 10+ messages in thread
From: rmccabe @ 2006-10-09 17:12 UTC (permalink / raw)
  To: cluster-devel.redhat.com

CVSROOT:	/cvs/cluster
Module name:	conga
Changes by:	rmccabe at sourceware.org	2006-10-09 17:12:29

Modified files:
	luci/cluster   : form-chooser form-macros 
	luci/site/luci/Extensions: cluster_adapters.py 
	luci/storage   : index_html 

Log message:
	more page title labels and miscellaneous other small fixes

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-chooser.diff?cvsroot=cluster&r1=1.9&r2=1.10
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/form-macros.diff?cvsroot=cluster&r1=1.78&r2=1.79
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.85&r2=1.86
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/index_html.diff?cvsroot=cluster&r1=1.6&r2=1.7

--- conga/luci/cluster/form-chooser	2006/10/09 16:16:11	1.9
+++ conga/luci/cluster/form-chooser	2006/10/09 17:12:26	1.10
@@ -14,10 +14,7 @@
     <span tal:omit-tag="" tal:condition="python: not ptype">
      <div metal:use-macro="here/form-macros/macros/entry-form"/>
     </span>
-    <span tal:omit-tag="" tal:condition="python: ptype == '0'">
-     <div metal:use-macro="here/form-macros/macros/entry-form"/>
-    </span>
-    <span tal:omit-tag="" tal:condition="python: ptype == '3'">
+    <span tal:omit-tag="" tal:condition="python: ptype == '0' or ptype == '1' or ptype == '2' or ptype == '3'">
      <div metal:use-macro="here/form-macros/macros/clusters-form"/>
     </span>
     <span tal:omit-tag="" tal:condition="python: ptype == '4'">
--- conga/luci/cluster/form-macros	2006/10/09 16:16:11	1.78
+++ conga/luci/cluster/form-macros	2006/10/09 17:12:28	1.79
@@ -25,6 +25,9 @@
 </div>
 
 <div metal:define-macro="clusters-form">
+	<script type="text/javascript">
+		set_page_title('Luci ??? cluster ??? cluster list');
+	</script>
 <div id="cluster_list">
 <div class="cluster" tal:repeat="clu clusystems">
 	<tal:block tal:define="global ragent python: here.getRicciAgent(clu)" />
--- conga/luci/site/luci/Extensions/cluster_adapters.py	2006/10/06 20:45:26	1.85
+++ conga/luci/site/luci/Extensions/cluster_adapters.py	2006/10/09 17:12:28	1.86
@@ -1,5 +1,6 @@
 import socket
 from ModelBuilder import ModelBuilder
+from xml.dom import minidom
 from ZPublisher import HTTPRequest
 import AccessControl
 from conga_constants import *
@@ -287,7 +288,21 @@
 	return (True, {'errors': errors, 'messages': messages})
 
 def validateServiceEdit(self, request):
-	return (True, {})
+	try:
+		form_xml = request['form_xml']
+		if not form_xml:
+			raise KeyError('form_xml must not be blank')
+	except KeyError, e:
+		return (False, {errors: ['No resource data was supplied for this service.']})
+
+	try:
+		doc = minidom.parseString(form_xml)
+		if not doc.firstChild:
+			raise
+	except:
+		return (False, {'errors': ['The resource data submitted for this service is not properly formed.']})
+		
+	return (True, {'messages': ['OK']})
 
 def validateServiceAdd(self, request):
 	return (True, {})
@@ -588,7 +603,7 @@
   try:
     pagetype = request[PAGETYPE]
   except KeyError, e:
-    pagetype = "0"
+    pagetype = '3'
 
 
   cldata = {}
@@ -667,7 +682,7 @@
   try:
     pagetype = request[PAGETYPE]
   except KeyError, e:
-    pagetype = "0"
+    pagetype = '3'
 
   try:
     url = request['URL']
--- conga/luci/storage/index_html	2006/08/03 18:56:09	1.6
+++ conga/luci/storage/index_html	2006/10/09 17:12:28	1.7
@@ -49,6 +49,7 @@
 
 
 <!--  async helper functions -->
+<script type="text/javascript" src="/luci/conga.js"></script>
 <script language="javascript" type="text/javascript">
 
 var xmlHttp_object = false;



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2007-09-25 22:47 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-02-23 22:07 [Cluster-devel] conga/luci cluster/form-chooser cluster/form-m rmccabe
  -- strict thread matches above, loose matches on Subject: below --
2007-09-25 22:47 rmccabe
2007-03-12  4:25 rmccabe
2007-03-12  4:24 rmccabe
2007-03-12  4:22 rmccabe
2006-12-21 21:26 kupcevic
2006-12-07 17:54 rmccabe
2006-12-06 18:38 rmccabe
2006-11-10 19:44 rmccabe
2006-10-09 17:12 rmccabe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).