commit 389271cf753fc863d75d042fd3208a6b0e2f463d
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Feb 21 22:31:39 2011 -0500
Fix fence brokenness exposed by the stricter xml parser
luci/controllers/cluster.py | 124 +++++++++++++++++++++++++----------------
luci/lib/ClusterConf/Fence.py | 15 +++++
luci/public/js/node.js | 33 +++++++++++
luci/templates/node.html | 34 ++++++------
4 files changed, 140 insertions(+), 66 deletions(-)
---
diff --git a/luci/controllers/cluster.py b/luci/controllers/cluster.py
index 524ceed..4fb9c28 100644
--- a/luci/controllers/cluster.py
+++ b/luci/controllers/cluster.py
@@ -167,73 +167,89 @@ class IndividualClusterController(BaseController):
flash(_('Unable to contact any nodes in this cluster'),
status="error")
redirect(tmpl_context.cluster_url)
+ cur_nodename = kw.get('node')
if kw.get("method_to_remove"):
- node = self.model.retrieveNodeByName(kw.get("node"))
+ node = self.model.retrieveNodeByName(cur_nodename)
methodname = kw.get("method_to_remove")
+ found_method = False
for child in node.getFenceNode().getChildren():
if child.getName() == methodname:
for child_device in child.getChildren():
node.removeFenceInstance(child, child_device)
+ found_method = True
node.getFenceNode().removeChild(child)
break
- self.model.setModified(True)
- rh.update_cluster_conf(self.model)
+ if found_method is True:
+ log.info('User "%s" removed method "%s" from node
"%s" in cluster "%s"'
+ % (self.username, methodname, cur_nodename, self.name))
+ self.model.setModified(True)
+ rh.update_cluster_conf(self.model)
+ else:
+ log.error('User "%s" failed to remove method "%s"
from node "%s" in cluster "%s"'
+ % (self.username, methodname, cur_nodename, self.name))
- if kw.get("fenceinst_to_remove") and
kw.get("fenceinst_to_remove_method"):
- node = self.model.retrieveNodeByName(kw.get("node"))
+ elif kw.get("fenceinst_to_remove") and
kw.get("fenceinst_to_remove_method"):
+ found_instance = False
+ node = self.model.retrieveNodeByName(cur_nodename)
fenceinst = kw.get("fenceinst_to_remove")
methodname = kw.get("fenceinst_to_remove_method")
for child in node.getFenceNode().getChildren():
if child.getName() == methodname:
- node.removeFenceInstance(child, child.children[int(fenceinst)-1])
- self.model.setModified(True)
- rh.update_cluster_conf(self.model)
+ node.removeFenceInstance(child, child.children[int(fenceinst) - 1])
+ found_instance = True
+ if found_instance is True:
+ log.info('User "%s" removed fence instance "%s"
from method "%s" from node "%s" in cluster "%s"'
+ % (self.username, fenceinst, methodname, cur_nodename, self.name))
+ self.model.setModified(True)
+ rh.update_cluster_conf(self.model)
+ else:
+ log.error('User "%s" failed to remove fence instance
"%s" from method "%s" from node "%s" in cluster
"%s"'
+ % (self.username, fenceinst, methodname, cur_nodename, self.name))
- if kw.get("moveup_method"):
- node = self.model.retrieveNodeByName(kw.get("node"))
+ elif kw.get("moveup_method"):
+ node = self.model.retrieveNodeByName(cur_nodename)
methodname = kw.get("moveup_method")
- levels = node.getFenceMethods()
- for level in levels:
- if level.getAttribute("name") == methodname:
- position = levels.index(level)
- if position > 0:
- levels.pop(position)
- levels.insert(position-1,level)
- self.model.setModified(True)
- rh.update_cluster_conf(self.model)
- break
-
- if kw.get("movedown_method"):
- node = self.model.retrieveNodeByName(kw.get("node"))
+ fence_elem = node.getFenceNode()
+ if fence_elem is not None:
+ mposition = fence_elem.findMethod(methodname)
+ if mposition is not None and mposition > 0:
+ fence_elem.moveMethodUp(mposition)
+ self.model.setModified(True)
+ rh.update_cluster_conf(self.model)
+ log.info('User "%s" moved up fence method
"%s" for node "%s" in cluster "%s"'
+ % (self.username, methodname, cur_nodename, self.name))
+
+ elif kw.get("movedown_method"):
+ node = self.model.retrieveNodeByName(cur_nodename)
methodname = kw.get("movedown_method")
+ fence_elem = node.getFenceNode()
levels = node.getFenceMethods()
- for level in levels:
- if level.getAttribute("name") == methodname:
- position = levels.index(level)
- if position < len(levels) - 1:
- levels.pop(position)
- levels.insert(position+1,level)
- self.model.setModified(True)
- rh.update_cluster_conf(self.model)
- break
-
- if command == "AddFence":
- node = self.model.retrieveNodeByName(kw.get("node"))
+ if fence_elem is not None:
+ mposition = fence_elem.findMethod(methodname)
+ if mposition is not None and mposition < len(levels) - 1:
+ fence_elem.moveMethodDown(mposition)
+ self.model.setModified(True)
+ rh.update_cluster_conf(self.model)
+ log.info('User "%s" moved down fence method
"%s" for node "%s" in cluster "%s"'
+ % (self.username, methodname, cur_nodename, self.name))
+
+ elif command == "AddFence":
+ node = self.model.retrieveNodeByName(cur_nodename)
levels = node.getFenceMethods()
fence_method = Method()
fence_method.addAttribute('name', '1')
if len(levels) > 0:
- methodname = kw['methodname']
+ methodname = kw.get('methodname')
fence_methods = node.getFenceMethods()
for i in fence_methods:
if i.getAttribute("name") == methodname:
fence_method = i
break
- parent_fencedev = kw['parent_fencedev'].replace('fd_',
'', 1)
+ parent_fencedev = kw.get('parent_fencedev').replace('fd_',
'', 1)
- retcode, retobj, retunfence = validate_fenceinstance(parent_fencedev,
kw['fence_type'], **kw)
+ retcode, retobj, retunfence = validate_fenceinstance(parent_fencedev,
kw.get('fence_type'), **kw)
if retcode is True:
# Add unfence section if requested.
if retunfence is not None:
@@ -251,21 +267,27 @@ class IndividualClusterController(BaseController):
if len(levels) == 0:
fence_node = node.getFenceNode()
fence_node.addChild(fence_method)
- flash(_('Updating fence settings'))
+
+ flash(_('Updating fence settings for node "%s"' %
cur_nodename))
+ log.info('User "%s" added a fence instance to fence method
"%s" for node "%s" in cluster "%s"'
+ % (self.username, methodname, cur_nodename, self.name))
self.model.setModified(True)
rh.update_cluster_conf(self.model)
else:
msgs = retobj
if msgs and len(msgs) > 0:
- flash(', '.join(msgs), status="error")
+ err_msg_str = ', '.join(msgs)
+ flash('%s' % err_msg_str, status="error")
+ log.error('User "%s" failed to add a fence instance to
fence method "%s" for node "%s" in cluster "%s": %s'
+ % (self.username, methodname, cur_nodename, self.name,
err_msg_str))
- if command == "EditFence":
- node = self.model.retrieveNodeByName(kw.get("node"))
+ elif command == "EditFence":
+ node = self.model.retrieveNodeByName(cur_nodename)
instance_id = kw.get("instance_id")
- (method_num,sep,fence_instance_id) = instance_id.partition('-')
+ (method_num, sep, fence_instance_id) = instance_id.partition('-')
# Create the fence device, and if it succeeds replace the old one with the
new one
- retcode, retobj, retunfence =
validate_fenceinstance(kw["fencedev"], kw['fence_type'], **kw)
+ retcode, retobj, retunfence =
validate_fenceinstance(kw.get('fencedev'), kw.get('fence_type'), **kw)
if retcode is True:
# Add 'unfence' section if requested, remove it otherwise.
old_device =
node.getFenceNode().children[int(method_num)].children[int(fence_instance_id)]
@@ -297,19 +319,23 @@ class IndividualClusterController(BaseController):
unfence.addChild(retunfence)
# ---
node.getFenceNode().children[int(method_num)].children[int(fence_instance_id)] = retobj
+ log.info('User "%s" edited "%s" fence instance of
fence method "%s" for node "%s" in cluster "%s"'
+ % (self.username, kw.get('fencedev'), method_num,
cur_nodename, self.name))
self.model.setModified(True)
rh.update_cluster_conf(self.model)
- if command == "AddFenceMethod":
- node = self.model.retrieveNodeByName(kw.get("node"))
+ elif command == "AddFenceMethod":
+ node = self.model.retrieveNodeByName(cur_nodename)
methodname = kw.get("newmethodname")
method = Method()
- method.addAttribute("name",methodname)
+ method.addAttribute("name", methodname)
node.getFenceNode().addChild(method)
+ log.info('User "%s" added fence method "%s" to node
"%s" in cluster "%s"'
+ % (self.username, methodname, cur_nodename, self.name))
self.model.setModified(True)
rh.update_cluster_conf(self.model)
- redirect('%s%s' % (tmpl_context.cluster_url, kw.get('node')))
+ redirect('%s%s' % (tmpl_context.cluster_url, cur_nodename))
# This processes all of the commands that we can apply to a node
@expose("luci.templates.node")
@@ -471,7 +497,7 @@ class IndividualClusterController(BaseController):
# For IP resources there is no name, just an IP Address
# and to make IP addresses work you need to add a .html
if res_type == 'ip':
- res_name = kw['address']
+ res_name = kw.get('address')
redir_fmt = '%s/%s.html'
else:
res_name = kw.get('resourcename')
diff --git a/luci/lib/ClusterConf/Fence.py b/luci/lib/ClusterConf/Fence.py
index 1fafbae..36ea9a4 100644
--- a/luci/lib/ClusterConf/Fence.py
+++ b/luci/lib/ClusterConf/Fence.py
@@ -13,3 +13,18 @@ class Fence(TagObject):
def __init__(self):
TagObject.__init__(self)
self.TAG_NAME = TAG_NAME
+
+ def findMethod(self, method_name):
+ for m in xrange(len(self.children)):
+ cur_m = self.children[m]
+ if cur_m.getAttribute("name") == method_name:
+ return m
+ return None
+
+ def moveMethodUp(self, method_index):
+ cur_method = self.children.pop(method_index)
+ self.children.insert(method_index - 1, cur_method)
+
+ def moveMethodDown(self, method_index):
+ cur_method = self.children.pop(method_index)
+ self.children.insert(method_index + 1, cur_method)
diff --git a/luci/public/js/node.js b/luci/public/js/node.js
index 672cff2..9262b42 100644
--- a/luci/public/js/node.js
+++ b/luci/public/js/node.js
@@ -63,3 +63,36 @@ function gen_fence_xml(form) {
}
form.submit();
}
+
+function fence_method_remove(fence_form_id, method_name) {
+ var form_elem = document.getElementById(fence_form_id);
+ if (form_elem && method_name) {
+ $(form_elem.method_to_remove).attr('value', method_name);
+ form_elem.submit();
+ }
+}
+
+function fence_method_moveup(fence_form_id, method_name) {
+ var form_elem = document.getElementById(fence_form_id);
+ if (form_elem && method_name) {
+ $(form_elem.moveup_method).attr('value', method_name);
+ form_elem.submit();
+ }
+}
+
+function fence_method_movedown(fence_form_id, method_name) {
+ var form_elem = document.getElementById(fence_form_id);
+ if (form_elem && method_name) {
+ $(form_elem.movedown_method).attr('value', method_name);
+ form_elem.submit();
+ }
+}
+
+function fence_instance_remove(fence_form_id, method_name, instance_name) {
+ var form_elem = document.getElementById(fence_form_id);
+ if (form_elem && method_name && instance_name) {
+ $(form_elem.fenceinst_to_remove_method).attr('value', method_name);
+ $(form_elem.fenceinst_to_remove).attr('value', instance_name);
+ form_elem.submit();
+ }
+}
diff --git a/luci/templates/node.html b/luci/templates/node.html
index 772bad1..e06e53a 100644
--- a/luci/templates/node.html
+++ b/luci/templates/node.html
@@ -52,7 +52,7 @@
</div>
</py:if>
- <form action="${'%snodes_cmd' % tmpl_context.cluster_url}"
method="post">
+ <form action="${tg.url('%snodes_cmd' % tmpl_context.cluster_url)}"
method="post">
<div class="sectionblock">
<xi:include href="submenu.html"/>
<div id="toolbar">
@@ -215,10 +215,10 @@
<div id="details_header">
<h3 py:content="name"/>
<div id="details_header_buttons">
- <a href="${tg.url('nodes_cmd?command=Reboot' +
'&name=' + name)}" id="dh_reboot"
title="reboot"><span
class="hide">reboot</span></a>
- <a href="${tg.url('nodes_cmd?command=Join+Cluster' +
'&name=' + name)}" id="dh_join"
title="join"><span class="hide">join</span></a>
- <a href="${tg.url('nodes_cmd?command=Leave+Cluster' +
'&name=' + name)}" id="dh_leave" title="leave
cluster"><span class="hide">leave cluster</span></a>
- <a href="${tg.url('nodes_cmd?command=Delete' +
'&name=' + name)}" id="dh_delete"
title="delete"><span
class="hide">delete</span></a>
+ <a href="${tg.url('%snodes_cmd?command=Reboot&name=%s' %
(tmpl_context.cluster_url, name))}" id="dh_reboot"
title="reboot"><span
class="hide">reboot</span></a>
+ <a
href="${tg.url('%snodes_cmd?command=Join+Cluster&name=%s' %
(tmpl_context.cluster_url, name))}" id="dh_join"
title="join"><span class="hide">join</span></a>
+ <a
href="${tg.url('%snodes_cmd?command=Leave+Cluster&name=%s' %
(tmpl_context.cluster_url, name))}" id="dh_leave" title="leave
cluster"><span class="hide">leave cluster</span></a>
+ <a href="${tg.url('%snodes_cmd?command=Delete&name=%s' %
(tmpl_context.cluster_url, name))}" id="dh_delete"
title="delete"><span
class="hide">delete</span></a>
</div>
<span class="details_header_info_label">Status</span>
<span class="details_header_info"
py:choose="details['clustered']">
@@ -232,7 +232,7 @@
<div class="details_section">
<h4>Properties</h4>
<div class="details_inner">
- <form action="${'%snodes_cmd?command=Update+Attributes' %
tmpl_context.cluster_url}" method="post"
+ <form action="${tg.url('%snodes_cmd?command=Update+Attributes' %
tmpl_context.cluster_url)}" method="post"
py:with="node_data = cluster_data.getNodeByName(name);
nodedbobj = db_helpers.get_cluster_node(tmpl_context.cluster_name,
name)">
<input type="hidden" name="name"
value="${name}"/>
@@ -320,7 +320,7 @@
fenceinst_num = 0
?>
<div class="details_inner">
- <form method="post" name="node_fence_form"
action="${tg.url('nodes_fence_cmd')}">
+ <form method="post" name="node_fence_form"
id="node_fence_form" action="${tg.url('%snodes_fence_cmd' %
tmpl_context.cluster_url)}">
<input type="hidden" name="method_to_remove"
value=""/>
<input type="hidden" name="fenceinst_to_remove"
value=""/>
<input type="hidden" name="fenceinst_to_remove_method"
value=""/>
@@ -337,16 +337,16 @@
<tbody>
<py:for each="order,(method,instances) in enumerate(fence_info)"
py:with="cur_dev_id=method">
- <tr>
- <td colspan="2">${method.getName().replace('
',' ')}</td>
+ <tr py:with="method_name = method.getName()">
+ <td colspan="2">${method_name.replace('
',' ')}</td>
<td align="right">
- <a py:if="order != 0" href=""
onclick="document.node_fence_form.moveup_method.value =
"${method.getName()}";document.node_fence_form.submit();return
false;">Move Up</a>
+ <a py:if="order != 0" href=""
onclick="fence_method_moveup('node_fence_form',
'${method_name}')">Move Up</a>
</td>
<td align="right">
- <a py:if="order != len(fence_info)-1" href=""
onclick="document.node_fence_form.movedown_method.value =
"${method.getName()}";document.node_fence_form.submit();return
false;">Move Down</a>
+ <a py:if="order != len(fence_info)-1" href=""
onclick="fence_method_movedown('node_fence_form',
'${method_name}')">Move Down</a>
</td>
<td align="right">
- <a href=""
onclick="document.node_fence_form.method_to_remove.value =
"${method.getName()}";document.node_fence_form.submit();return
false;">Remove</a>
+ <a href=""
onclick="fence_method_remove('node_fence_form',
'${method_name}')">Remove</a>
</td>
</tr>
@@ -371,7 +371,7 @@
<div class="hidden">
<div id="edit_fencedev_dialog_${instance_id}">
<form name="filler"/>
- <form name="edit_fence_device_${instance_id}"
method="post"
action="${tg.url('nodes_fence_cmd?command=EditFence')}">
+ <form name="edit_fence_device_${instance_id}"
method="post"
action="${tg.url('%snodes_fence_cmd?command=EditFence' %
tmpl_context.cluster_url)}">
<input type="hidden" name="node"
value="${name}"/>
<input type="hidden" name="instance_id"
value="${instance_id}"/>
<input type="hidden" name="fencedev"
value="${agent_alias}"/>
@@ -409,7 +409,7 @@
<td><a href="#"
onclick="$('#edit_fencedev_dialog_${instance_id}').dialog('open')">${agent_alias}</a></td>
<td>${agent_name}</td>
<td align="right">
- <a href=""
onclick="document.node_fence_form.fenceinst_to_remove_method.value =
"${method.getName()}";document.node_fence_form.fenceinst_to_remove.value
= "${fenceinst_num}";document.node_fence_form.submit();return
false;">
+ <a href=""
onclick="fence_instance_remove('node_fence_form',
'${method.getName()}', '${fenceinst_num}')">
<img src="/images/delete-grey.png"/>
</a>
</td>
@@ -429,7 +429,7 @@
</py:for>
<tr>
<td colspan="3">
- <input type="button"
py:if="len(cluster_data.getFenceDevices()) > 0" value="Add Fence
Instance" class="button small silver"
onclick="$(create_fence_device.methodname).attr('value','${method.getName()}');$('#create_fencedev_dialog').dialog('open')"/>
+ <input type="button"
py:if="len(cluster_data.getFenceDevices()) > 0" value="Add Fence
Instance" class="button small silver"
onclick="$('#create_fence_device_form
input[name=methodname]').attr('value','${method.getName()}');$('#create_fencedev_dialog').dialog('open')"/>
</td>
</tr>
</table>
@@ -483,7 +483,7 @@
<div py:if="name is not None" class="hidden">
<div id="create_fencedev_dialog">
- <form name="create_fence_device" method="post"
action="${tg.url('nodes_fence_cmd?command=AddFence')}">
+ <form name="create_fence_device"
id="create_fence_device_form" method="post"
action="${tg.url('%snodes_fence_cmd?command=AddFence' %
tmpl_context.cluster_url)}">
<input type="hidden" name="node"
value="${name}"/>
<input type="hidden" name="methodname"
value=""/>
${fence_device_select(cluster_data, 'fence_form_area')}
@@ -498,7 +498,7 @@
</div>
<div class="hidden">
<div id="create_fencemethod_dialog">
- <form name="create_fence_method" method="post"
action="${tg.url('nodes_fence_cmd?command=AddFenceMethod')}">
+ <form name="create_fence_method" method="post"
action="${tg.url('%snodes_fence_cmd?command=AddFenceMethod' %
tmpl_context.cluster_url)}">
<input type="hidden" name="node"
value="${name}"/>
Method Name:<input type="text" name="newmethodname"
value="Method"/>
<div class="row">