[luci] Fix rhbz#614963: BaseException.message deprecated
by Jan Pokorný
commit 5efb11dae9a80b94ed9283b8fbe0b1c53af7166d
Author: Jan Pokorny <jpokorny(a)redhat.com>
Date: Fri Aug 27 21:45:37 2010 +0200
Fix rhbz#614963: BaseException.message deprecated
luci/lib/async_helpers.py | 4 ++-
luci/lib/ricci_communicator.py | 42 ++++++++++++++-------------------------
luci/lib/ricci_queries.py | 19 ++++++++++-------
3 files changed, 29 insertions(+), 36 deletions(-)
---
diff --git a/luci/lib/async_helpers.py b/luci/lib/async_helpers.py
index 7befc52..a205df8 100644
--- a/luci/lib/async_helpers.py
+++ b/luci/lib/async_helpers.py
@@ -35,7 +35,9 @@ def get_node_list(host, passwd):
if not node_names or len(node_names) < 1:
return { 'errors': [ _('Unable to retrieve the list of cluster nodes from "%s"') % host ]}
except Exception, e:
- return { 'errors': [ _('Unable to connect to host "%s": %s') % (host, e.message) ] }
+ # Presumably only RicciError or RicciQueriesError could be caught, both of which
+ # have exactly one argument.
+ return { 'errors': [ _('Unable to connect to host "%s": %s') % (host, e.args[0]) ] }
return { 'nodes': node_names, 'cluster': cluster_name }
def cluster_is_busy(cluster_name):
diff --git a/luci/lib/ricci_communicator.py b/luci/lib/ricci_communicator.py
index 215adf7..7a31fb9 100644
--- a/luci/lib/ricci_communicator.py
+++ b/luci/lib/ricci_communicator.py
@@ -47,7 +47,7 @@ class RicciCommunicator:
except socket.error, msg:
s = None
continue
-
+
self.ss = ssl.wrap_socket(s,
certfile=self.__cert_file,
keyfile=self.__privkey_file,
@@ -55,13 +55,13 @@ class RicciCommunicator:
self.ss.settimeout(self.__timeout_init)
self.ss.connect((self.__hostname, self.__port))
except Exception, e:
- if e.message:
- errmsg = 'Unable to establish an SSL connection to %s:%d: %s' \
- % (self.__hostname, self.__port, e.message)
- elif len(e.args) > 1:
+ if len(e.args) > 1:
+ # Case for ssl.SSLError and socket.error that has 'args'
+ # formed by (errno, string) pair.
errmsg = 'Unable to establish an SSL connection to %s:%d: %s' \
% (self.__hostname, self.__port, e.args[1])
else:
+ # Other cases (if any); 'len(e.args) == 1' not expected.
errmsg = 'Unable to establish an SSL connection to %s:%d' \
% (self.__hostname, self.__port)
log.exception(errmsg)
@@ -71,7 +71,7 @@ class RicciCommunicator:
try:
hello = self.__receive(self.__timeout_init)
if LUCI_LOG_DEBUG_NETWORK is True:
- log.debug('Recv header from %s:%d "%s"'
+ log.debug('Recv header from %s:%d "%s"'
% (self.__hostname, self.__port, hello.toxml()))
except:
log.exception('Error receiving header from %s:%d'
@@ -203,7 +203,7 @@ class RicciCommunicator:
pass
except Exception, e:
errstr = 'Error unauthenticating to the ricci agent at %s:%d: %s' \
- % (self.__hostname, self.__port, e.message)
+ % (self.__hostname, self.__port, e.args[0])
log.exception(errstr)
raise RicciError, errstr
return True
@@ -385,16 +385,10 @@ class RicciCommunicator:
try:
self.ss.settimeout(timeout)
self.ss.write(xml_doc.toxml())
- except Exception, e:
- if e.message:
- errstr = 'Error sending batch command to %s:%d: %s' \
- % (self.__hostname, self.__port, e.message)
- elif len(e.args) > 1:
- errstr = 'Error sending batch command to %s:%d: %s' \
- % (self.__hostname, self.__port, e.args[1])
- else:
- errstr = 'Error sending batch command to %s:%d' \
- % (self.__hostname, self.__port)
+ except ssl.SSLError, e:
+ # Only ssl.SSLError expected which is formed by (errno, string) pair.
+ errstr = 'Error sending batch command to %s:%d: %s' \
+ % (self.__hostname, self.__port, e.args[1])
if LUCI_LOG_DEBUG_NETWORK is True:
log.debug("%s | XML: %s" % (errstr, xml_doc.toxml()))
@@ -425,16 +419,10 @@ class RicciCommunicator:
% (xml_in, self.__hostname, self.__port))
if len(cur_chunk) == 0:
break
- except Exception, e:
- if e.message:
- errstr = 'Error reading from %s:%d: %s' \
- % (self.__hostname, self.__port, e.message)
- elif len(e.args) > 1:
- errstr = 'Error reading from %s:%d: %s' \
- % (self.__hostname, self.__port, e.args[1])
- else:
- errstr = 'Error reading from %s:%d' \
- % (self.__hostname, self.__port)
+ except ssl.SSLError, e:
+ # Only ssl.SSLError expected which is formed by (errno, string) pair.
+ errstr = 'Error reading from %s:%d: %s' \
+ % (self.__hostname, self.__port, e.args[1])
log.exception(errstr)
raise RicciError, errstr
diff --git a/luci/lib/ricci_queries.py b/luci/lib/ricci_queries.py
index e0bb625..e609d44 100644
--- a/luci/lib/ricci_queries.py
+++ b/luci/lib/ricci_queries.py
@@ -10,6 +10,9 @@ from pylons.i18n import ugettext as _
from xml.dom import minidom
from ricci_communicator import batch_status
+class RicciQueriesError(Exception):
+ pass
+
def addClusterNodeBatch(model,
install_base,
install_services,
@@ -249,7 +252,7 @@ def batchAttemptResult(doc):
try:
batch = doc.getElementsByTagName('batch')
if not batch or len(batch) < 1:
- raise Exception, 'no batch tag was found'
+ raise RicciQueriesError, 'no batch tag was found'
except Exception, e:
return (None, None)
@@ -281,7 +284,7 @@ def getClusterStatusBatch(rc):
try:
cluster_node = cluster_tags[0]
if not cluster_node:
- raise Exception, 'element 0 is None'
+ raise RicciQueriesError, 'element 0 is None'
except Exception, e:
return None
@@ -352,7 +355,7 @@ def getNodeLogs(rc):
try:
log_entries = ricci_xml.getElementsByTagName('logentry')
if not log_entries or len(log_entries) < 1:
- raise Exception, 'no log data is available.'
+ raise RicciQueriesError, 'no log data is available.'
except Exception, e:
return None
@@ -520,7 +523,7 @@ def svc_manage(rc, hostname, servicename, op):
if op == 'restart' or op == 'start' or op == 'stop':
svc_func = op
else:
- raise Exception, op
+ raise RicciQueriesError, op
except Exception, e:
elem.setAttribute('message', 'Unknown operation: %s' % str(e))
doc.appendChild(elem)
@@ -588,7 +591,7 @@ def nodeIsVirtual(rc):
try:
name = i.getAttribute('name')
if not name:
- raise Exception, 'name is blank'
+ raise RicciQueriesError, 'name is blank'
if name == 'success':
result = i.getAttribute('value')
if result == 'true':
@@ -598,7 +601,7 @@ def nodeIsVirtual(rc):
if result == 'true':
virtual = True
else:
- raise Exception, 'unexpected attribute name: %s' % name
+ raise RicciQueriesError, 'unexpected attribute name: %s' % name
except Exception, e:
pass
@@ -628,7 +631,7 @@ def extractDaemonInfo(bt_node):
try:
name = node.getAttribute('name')
if not name:
- raise Exception, 'No name'
+ raise RicciQueriesError, 'No name'
except Exception, e:
name = '[unknown]'
svchash['name'] = name
@@ -659,7 +662,7 @@ def getClusterConf(rc):
ricci_xml = rc.batch_run(batch_str, async=False)
try:
if not ricci_xml:
- raise Exception, 'no XML response'
+ raise RicciQueriesError, 'no XML response'
except Exception, e:
return None
13 years, 8 months
[luci] Re: Fix rhbz#536841: forgotten logging
by Jan Pokorný
commit adb85696f14d412c5b3ec9cde65bdd81e161c5dc
Author: Jan Pokorny <jpokorny(a)redhat.com>
Date: Mon Aug 23 16:37:58 2010 +0200
Re: Fix rhbz#536841: forgotten logging
luci/lib/flash2.py | 11 ++---------
1 files changed, 2 insertions(+), 9 deletions(-)
---
diff --git a/luci/lib/flash2.py b/luci/lib/flash2.py
index 777c58f..a0d2772 100644
--- a/luci/lib/flash2.py
+++ b/luci/lib/flash2.py
@@ -5,12 +5,9 @@
from tg import session
from paste.registry import StackedObjectProxy
-import logging
-log = logging.getLogger(__name__)
-
-
__all__ = ['Flash2', 'flash2']
+
class _Flash2Message(object):
def __init__(self, msg, cls='info', html=False, hideable=False):
self.message = msg
@@ -55,7 +52,7 @@ class Flash2:
Note the same can be achieved by:
flash2.info('This is info.').warning('This is warning').flush()
- As shown, you have always use 'flush' method in order to store the state
+ As shown, you always have to use 'flush' method in order to store the state
of flash messages to session's data which are read on the templates side
afterwards and displayed on respective page. During (the first) iteration
over the instance of this class, all messages are consequently popped
@@ -64,7 +61,6 @@ class Flash2:
"""
def __init__(self):
- log.info("Creating _Flash2, id = %d" % id(self))
self.__messages = []
#self.__messages_dict = {'info':[], 'warning':[], 'error':[], 'ok': []}
@@ -83,9 +79,6 @@ class Flash2:
raise StopIteration
return DeletingIterator(self.__messages)
- def __del__(self):
- log.info("Deleting _Flash2, id = %d", id(self))
-
def __repr__(self):
return "<Flash2 with messages: %s>" % ", ".join(map(lambda m: str(m), self.get_messages()))
13 years, 8 months
[luci] Fix rhbz#536841: Ability to change number of votes
by Jan Pokorný
commit 2f2f0217d8a3de719cea980384804c315fa9f348
Author: Jan Pokorny <jpokorny(a)redhat.com>
Date: Fri Aug 20 19:30:50 2010 +0200
Fix rhbz#536841: Ability to change number of votes
luci/controllers/cluster.py | 21 +++++-
luci/controllers/root.py | 7 ++-
luci/lib/ClusterConf/Cluster.py | 28 +++++++-
luci/lib/flash2.py | 126 +++++++++++++++++++++++++++++++++++++++
luci/public/css/node.css | 10 +++
luci/public/css/style.css | 44 +++++++++-----
luci/templates/configure.html | 25 +++++---
luci/templates/master.html | 13 ++++-
luci/templates/node.html | 30 ++++++++-
9 files changed, 263 insertions(+), 41 deletions(-)
---
diff --git a/luci/controllers/cluster.py b/luci/controllers/cluster.py
index 86bc1e0..166b11a 100644
--- a/luci/controllers/cluster.py
+++ b/luci/controllers/cluster.py
@@ -19,6 +19,7 @@ from pylons.i18n import ugettext as _
from luci.lib.base import BaseController
from luci.lib.db_helpers import get_cluster_list, get_model_for_cluster, get_status_for_cluster, db_remove_cluster, get_agent_for_cluster, get_cluster_db_obj
import luci.lib.ricci_helpers as rh
+from luci.lib.flash2 import flash2
import luci.widget_validators.validate_cluster_prop as vcp
from luci.widget_validators.validate_create_cluster_form import validate_create_cluster_form, validate_node_add_form
from luci.widget_validators.validate_fence import validateNewFenceDevice, validateFenceDevice
@@ -303,7 +304,7 @@ class IndividualClusterController(BaseController):
rh.update_cluster_conf(self.model)
redirect('%s%s' % (tmpl_context.cluster_url, kw.get('node')))
-
+
# This processes all of the commands that we can apply to a node
@expose("luci.templates.node")
def nodes_cmd(self, command=None, **kw):
@@ -351,6 +352,18 @@ class IndividualClusterController(BaseController):
flash(_("Deleting nodes: %s") % ', '.join(cur_list),
status='info')
rh.cluster_node_delete(self.name, self.model, cur_list)
+ elif command == 'Update Attributes':
+ node = self.model.retrieveNodeByName(cur_list[0])
+ votes = kw.get('votes', '1')
+ node.addAttribute('votes', votes)
+ log.info('User "%s" changed properties for node "%s" from cluster "%s"'
+ % (self.username, cur_list[0], self.name))
+ flash2.info(_('Updating properties of node: %s') % cur_list[0])
+ if int(votes) > 1:
+ flash2.warning(_('Warning: Setting number of votes greater than 1 for any node within cluster will disable Quorum Disk functionality.'))
+ flash2.flush()
+ self.model.setModified(True)
+ rh.update_cluster_conf(self.model)
else:
log.error('User "%s" submitted unknown command "%s" for nodes "%s" from cluster "%s"' % (self.username, command, ', '.join(cur_list), self.name))
flash(_('An unknown command "%s" was given for nodes "%s"')
@@ -373,7 +386,7 @@ class IndividualClusterController(BaseController):
def resources_cmd(self, command=None, **kw):
self.get_model()
tmpl_context.cluster_url = '/cluster/%s/resources' % self.name
-
+
if not self.model:
flash(_('Unable to contact any nodes in this cluster'),
status="error")
@@ -481,7 +494,7 @@ class IndividualClusterController(BaseController):
flash(_('Unable to contact any nodes in this cluster'),
status="error")
redirect(tmpl_context.cluster_url)
-
+
preferred_node = kw.get('preferred_node')
cur_list = []
@@ -612,7 +625,7 @@ class IndividualClusterController(BaseController):
flash(_('The settings of exactly one failover domain may be updated at one time'),
status='error')
redirect(tmpl_context.cluster_url)
-
+
if command == 'update_settings':
vret = vcp.validate_fdom_prop_settings_form(self.model, **kw)
if vret[0] is True:
diff --git a/luci/controllers/root.py b/luci/controllers/root.py
index 1d11cd4..82e8810 100644
--- a/luci/controllers/root.py
+++ b/luci/controllers/root.py
@@ -6,6 +6,7 @@ from pylons.i18n import ugettext as _
from repoze.what import predicates
from luci.lib.base import BaseController
+from luci.lib.flash2 import Flash2, flash2
from luci.controllers.error import ErrorController
from luci.controllers.cluster import ClusterController
@@ -37,6 +38,10 @@ class RootController(BaseController):
def __call__(self, environ, start_response):
"""Invoke the Controller"""
+
+ # Register flash2 component for thread/request-local use.
+ environ['paste.registry'].register(flash2, Flash2())
+
tmpl_context.title_list = []
tmpl_context.already_used = dict()
tmpl_context.already_used.setdefault(False)
@@ -49,7 +54,7 @@ class RootController(BaseController):
async = AsyncController()
# METHODS OF THE ROOT CONTROLLER
-
+
@expose('luci.templates.index')
def index(self):
"""Handle the front-page."""
diff --git a/luci/lib/ClusterConf/Cluster.py b/luci/lib/ClusterConf/Cluster.py
index 17c1e66..ecba069 100644
--- a/luci/lib/ClusterConf/Cluster.py
+++ b/luci/lib/ClusterConf/Cluster.py
@@ -35,12 +35,32 @@ class Cluster(TagObject):
#self.is_cfg_version_dirty = True
def doesClusterUseQuorumDisk(self):
+ """Returns a pair (A, B) describing Quorum Disk situation within cluster.
+
+ A ... whether 'quorumd' xml-node present in cluster.conf
+ B ... whether all nodes within cluster have either 'votes' attribute equal to '1'
+ or no such attribute (which defaults to '1' automatically)
+
+ """
+ clusternodes_ptr = None
+ qdisk_found = False
kids = self.getChildren()
for kid in kids:
- if kid.getTagName().strip() == "quorumd":
- return True
-
- return False
+ kid_tag_name = kid.getTagName()
+ qdisk_found = qdisk_found or (kid_tag_name == "quorumd")
+ if kid_tag_name == "clusternodes":
+ clusternodes_ptr = kid
+ if qdisk_found:
+ break
+ if clusternodes_ptr == None:
+ return qdisk_found, True
+ else:
+ qdisk_supported = True
+ for kid in clusternodes_ptr.getChildren():
+ if kid.getTagName() == 'clusternode' \
+ and kid.getAttribute('votes') != None:
+ qdisk_supported = qdisk_supported and kid.getAttribute('votes') == '1'
+ return qdisk_found, qdisk_supported
def getQuorumdPtr(self):
kids = self.getChildren()
diff --git a/luci/lib/flash2.py b/luci/lib/flash2.py
new file mode 100644
index 0000000..777c58f
--- /dev/null
+++ b/luci/lib/flash2.py
@@ -0,0 +1,126 @@
+# Original published by Ansel at
+# http://groups.google.com/group/turbogears/browse_thread/thread/c86f1c18d6...
+# Slighly edited to fit current version of TG2 and project requirements.
+
+from tg import session
+from paste.registry import StackedObjectProxy
+
+import logging
+log = logging.getLogger(__name__)
+
+
+__all__ = ['Flash2', 'flash2']
+
+class _Flash2Message(object):
+ def __init__(self, msg, cls='info', html=False, hideable=False):
+ self.message = msg
+ self.css = cls
+ self.html = html
+ self.hideable = hideable
+ self.hash = id(self)
+
+ def __repr__(self):
+ return "<_Flash2Message: %s>" % self.__str__()
+
+ def __str__(self):
+ return "%s [%s]" % (self.message, self.css)
+
+
+class Flash2:
+ """A more advanced replacement for TurboGears2 built-in ``flash'' functionality.
+
+ It is intended to use this component in a local/request-local manner
+ (singleton object of this class) which can be reached this way:
+
+ 1. Register instance of this class together with 'flash2' proxy object
+ exported by this module with paste.registry object in your framework
+ (it is supposed that this middleware is plugged-in0.
+ For TurboGears2, you can use following in your root controller:
+
+ from luci.lib.flash2 import flash2, Flash2
+ class RootController(BaseController):
+ def __call__(self, environ, start_response):
+ environ['paste.registry'].register(flash2, Flash2())
+ # you code
+
+ 2. In the module/controller where you want to use the instance of this class,
+ just import 'flash2' proxy object exported by this module. Then, simply
+ use flash2 as if it was directly the instance of this class.
+
+ Example usage:
+ flash2.info('This is info.')
+ flash2.warning('This is warning.')
+ flash2.flush()
+
+ Note the same can be achieved by:
+ flash2.info('This is info.').warning('This is warning').flush()
+
+ As shown, you have always use 'flush' method in order to store the state
+ of flash messages to session's data which are read on the templates side
+ afterwards and displayed on respective page. During (the first) iteration
+ over the instance of this class, all messages are consequently popped
+ making this instance messages-free. That's why this iteration is intended
+ way of use on the templates side.
+
+ """
+ def __init__(self):
+ log.info("Creating _Flash2, id = %d" % id(self))
+ self.__messages = []
+ #self.__messages_dict = {'info':[], 'warning':[], 'error':[], 'ok': []}
+
+ def __iter__(self):
+ class DeletingIterator:
+ def __init__(self, messages):
+ self.__messages = messages
+ def __iter__(self):
+ return self
+ def next(self):
+ try:
+ # Note: self.__messages_dict should be handled if used.
+ item = self.__messages.pop(0)
+ return item
+ except IndexError:
+ raise StopIteration
+ return DeletingIterator(self.__messages)
+
+ def __del__(self):
+ log.info("Deleting _Flash2, id = %d", id(self))
+
+ def __repr__(self):
+ return "<Flash2 with messages: %s>" % ", ".join(map(lambda m: str(m), self.get_messages()))
+
+ def __add_message(self, msg, cls, html=False, hideable=False):
+ m = _Flash2Message(msg, cls, html, hideable)
+ self.__messages.append(m)
+ #if cls not in self.__messages_dict:
+ # self.__messages_dict[cls] = []
+ #self.__messages_dict[cls].append(m)
+ return self
+
+ def flush(self):
+ session['flash2'] = self
+ session.save()
+
+ def get_messages(self):
+ return self.__messages[:]
+
+ #def get_messages_dict(self)
+ # return self.__messages_dict.copy()
+
+ #---
+
+ def info(self, msg, html=False, hideable=True):
+ return self.__add_message(msg, 'info', html, hideable)
+
+ def warning(self, msg, html=False, hideable=True):
+ return self.__add_message(msg, 'warning', html, hideable)
+
+ def error(self, msg, html=False, hideable=False):
+ return self.__add_message(msg, 'error', html, hideable)
+
+ def ok(self, msg, html=False, hideable=True):
+ return self.__add_message(msg, 'ok', html, hideable)
+
+
+# Proxy object as mentioned in Flash2 class doc.
+flash2 = StackedObjectProxy()
diff --git a/luci/public/css/node.css b/luci/public/css/node.css
index 9062ede..9c4e049 100644
--- a/luci/public/css/node.css
+++ b/luci/public/css/node.css
@@ -19,6 +19,16 @@
/* details */
+/* attributes setting */
+
+#node_tattr {
+ margin: 0 15em 0 0;
+}
+
+.node_tattr_input {
+ padding: 8px 0 8px 5px;
+}
+
/* list of services */
#node_tservices tr {
diff --git a/luci/public/css/style.css b/luci/public/css/style.css
index f0590cb..9143260 100644
--- a/luci/public/css/style.css
+++ b/luci/public/css/style.css
@@ -68,7 +68,7 @@ ul.mainmenu li {
}
ul.mainmenu li a {
- background:transparent url(../images/breadcrumb_separator_0.png) no-repeat scroll 100% 50%;
+ background:transparent url(../images/breadcrumb_separator_0.png) no-repeat scroll 100% 50%;
color: #a4c9dd;
float: left;
display: block;
@@ -162,7 +162,7 @@ ul.headermenu li {
ul.headermenu li a {
color:#fff;
- text-decoration: none;
+ text-decoration: none;
}
#wrapper {
@@ -280,7 +280,7 @@ form>input.text, input.text {
padding: 3px;
border:1px solid #CAD0D4;
font-size: 12px;
- font-family:"Droid Sans","Lucida Grande","Lucida Sans Unicode",geneva,verdana,sans-serif;
+ font-family:"Droid Sans","Lucida Grande","Lucida Sans Unicode",geneva,verdana,sans-serif;
}
input.checkbox, input.radio {
@@ -302,7 +302,7 @@ input.checkbox, input.radio {
font-weight: bold;
padding: .5em 2em .55em;
text-shadow: 0 1px 1px rgba(0,0,0,.3);
- -webkit-border-radius: .5em;
+ -webkit-border-radius: .5em;
-moz-border-radius: .5em;
border-radius: .5em;
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,.2);
@@ -398,7 +398,7 @@ input.checkbox, input.radio {
}
table.clusternodes, table#clusternodes, table#addclusternode, table#qdisk_heuristics {
- width: auto;
+ width: auto;
}
table.clusternodes, table#clusternodes td, table#addclusternode td, table#qdisk_heuristics td{
@@ -479,14 +479,14 @@ form>h2 {
border-radius: 2px;
-webkit-box-shadow: 0 1px 1px #fff;
-moz-box-shadow: 0 1px 1px #fff;
- box-shadow: 0 1px 1px #fff;
+ box-shadow: 0 1px 1px #fff;
}
ul#clusterlist {
border-top: 1px solid #cad0d4;
- font-size: 12px;
+ font-size: 12px;
margin-top: 14px;
- padding-top: 14px;
+ padding-top: 14px;
}
.sidenav ul#clusterlist li a {
@@ -504,7 +504,7 @@ ul#clusterlist li a.problem {
.sidenav ul#clusterlist li a.current {
background-color: #d2e4f0;
color: #000;
- border: 1px solid #c5ddeb;
+ border: 1px solid #c5ddeb;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
@@ -598,25 +598,28 @@ span.code {
background:#EEEEEE none repeat scroll 0% 0%;
font-weight:bold;
}
-#flash, .notice {
+.message, .notice {
font-size:120%;
font-weight:normal;
margin:0 auto 0.5em;
}
-#flash div, .notice {
+.message div, .notice {
padding:20px 15px 20px 65px;
}
-#flash .ok {
+.message #flash, .notice {
+padding:0;
+}
+.message .ok {
background:#d8ecd8 url(../images/ok.png) no-repeat scroll 10px center;
}
-#flash .warning {
+.message .warning {
background:#fff483 url(../images/warning.png) no-repeat scroll 10px center;
}
-#flash .error {
+.message .error {
background:#f9c5c1 url(../images/error.png) no-repeat scroll 10px center;
}
-#flash .alert,
-#flash .info {
+.message .alert,
+.message .info {
background:#e9f4fa url(../images/info.png) no-repeat scroll 10px center;
}
.notice {
@@ -632,3 +635,12 @@ clear:both;
.hidden {
display: none ! important;
}
+
+.hide_btn {
+ float: right;
+}
+
+.important {
+ color: red;
+ padding: 1em 0em;
+}
diff --git a/luci/templates/configure.html b/luci/templates/configure.html
index 98bedf6..0ffc436 100644
--- a/luci/templates/configure.html
+++ b/luci/templates/configure.html
@@ -37,7 +37,7 @@
<script type="text/javascript">
$(function() {
function runEffect() {
-
+
$("#advanced").toggle("blind",{},500);
};
@@ -61,7 +61,7 @@
<h2>General Properties</h2>
<div class="row"><label>Cluster Name</label>
<input name="clusterName" type="text" class="text" value="${tmpl_context.cluster_name}" disabled="disabled" />
- </div>
+ </div>
<div class="row"><label>Configuration Version</label>
<input type="text" class="text" name="config_version" value="${cluster_data and cluster_data.getClusterConfigVersion()}"/>
</div>
@@ -75,7 +75,7 @@
<h2>Fence Daemon Properties</h2>
<div class="row"><label>Post Fail Delay (seconds)</label>
<input type="text" class="text" name="post_fail_delay" value="${cluster_data and cluster_data.getFenceDaemonPtr().getAttribute('post_fail_delay')}"/>
- </div>
+ </div>
<div class="row"><label>Post Join Delay (seconds)</label>
<input type="text" class="text" name="post_join_delay" value="${cluster_data and cluster_data.getFenceDaemonPtr().getAttribute('post_join_delay')}"/>
</div>
@@ -100,14 +100,14 @@
<input name="multicast" value="multicast_manual" class="radio" type="radio"
py:attrs="cluster_data and cluster_data.getMcastAddr() != None and {'checked': 'checked'} or {}"/>
<label class="choice">Specify the multicast address manually</label>
- <br />
+ <br />
<label class=" indent">Multicast address</label>
<input type="text" class="text" name="mcast_address" value="${cluster_data and cluster_data.getMcastAddr()}"/>
<br />
<input name="multicast" value="broadcast" class="radio" type="radio"
py:attrs="cluster_data and cluster_data.get_cluster_broadcast() is True and {'checked': 'checked'} or {}"/>
<label class="choice">Use broadcast (demos only - no production support)</label>
- </div>
+ </div>
<div class="row"><div id="button"><button class="button small silver">Show Advanced Properties</button></div>
</div>
@@ -122,19 +122,24 @@
</div>
</form>
</div>
- <div id="tabs-4" py:with="quorumd_ptr = cluster_data and cluster_data.quorumd_ptr">
+ <div id="tabs-4" py:with="quorumd_ptr = cluster_data and cluster_data.quorumd_ptr;
+ qdisk_found, qdisk_supported = cluster_data and cluster_data.getClusterPtr().doesClusterUseQuorumDisk();
+ qdisk_used = qdisk_found and qdisk_supported">
<form action="${tg.url(configure_cmd)}" method="post">
<input type="hidden" name="page" value="QDisk" />
<input type="hidden" name="command" value="Update" />
<h2>Quorum Disk Configuration</h2>
<div class="row">
- <input name="quorumd" type="radio" class="radio" value="false"
+ <div py:if="not qdisk_supported" class="important">
+ Quorum Disk will not be used unless each node of the cluster has only 1 vote!
+ </div>
+ <input name="quorumd" type="radio" class="radio" value="false"
onclick="disableChildrenInput('qdisk_config')"
- py:attrs="not quorumd_ptr and {'checked': ''} or {}"/><label class="choice">Do not use a Quorum Disk</label>
+ py:attrs="not qdisk_used and {'checked': 'checked'} or {}"/><label class="choice">Do not use a Quorum Disk</label>
<br />
<input name="quorumd" type="radio" class="radio" value="true"
onclick="enableChildrenInput('qdisk_config')"
- py:attrs="quorumd_ptr and {'checked': ''} or {}"/><label class="choice">Use a Quorum Disk</label>
+ py:attrs="qdisk_used and {'checked': 'checked'} or {}"/><label class="choice">Use a Quorum Disk</label>
</div>
<div id="qdisk_config">
@@ -234,7 +239,7 @@
</table>
<tr>
<td><input type="button" class="button small silver" value="Add Another Heuristic" onclick="add_qdisk_heuristic()" /></td>
- </tr>
+ </tr>
</fieldset>
</div>
<div class="row"><input type="submit" class="button formsubmit blue" value="Apply"/>
diff --git a/luci/templates/master.html b/luci/templates/master.html
index 5b37d77..3ae5411 100644
--- a/luci/templates/master.html
+++ b/luci/templates/master.html
@@ -40,8 +40,17 @@
<div id="content">
<py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
- <div py:if="flash" py:content="XML(flash)" />
- </py:with>
+ <div py:if="flash" py:content="XML(flash)" class="message"/>
+ </py:with>
+ <py:if test="'flash2' in session">
+ <div py:for="message in session['flash2']" class="message" id="${message.hash}">
+ <div py:if="message.hideable" class="hide_btn">
+ <a href="#" onclick="$('#${message.hash}').hide('blind',{},500,function () {});">Hide</a>
+ </div>
+ <div py:if="message.html" class="${message.css}" py:content="XML(message.message)"/>
+ <div py:if="not message.html" class="${message.css}" py:content="message.message"/>
+ </div>
+ </py:if>
<py:if test="'show_sidebar' in dir(tmpl_context) and tmpl_context.show_sidebar">
<xi:include href="mainmenu.html" />
diff --git a/luci/templates/node.html b/luci/templates/node.html
index 5956048..599a717 100644
--- a/luci/templates/node.html
+++ b/luci/templates/node.html
@@ -174,7 +174,7 @@
<div id="not_selected" py:choose="cluster_status and len(cluster_status.nodes) or 'unknown'">
<py:when test="'unknown'">
Unable to contact any of the nodes in this cluster.
- </py:when>
+ </py:when>
<py:when test="0">No item to display</py:when>
<py:otherwise>
Select an item to view details
@@ -202,6 +202,28 @@
</span>
</div>
+ <!--! DETAILS - attributes section. -->
+ <div class="details_section">
+ <h4>Properties</h4>
+ <div class="details_inner">
+ <form action="${'%snodes_cmd?command=Update+Attributes' % tmpl_context.cluster_url}" method="post"
+ py:with="node_data = cluster_data.getNodeByName(name)">
+ <input type="hidden" name="name" value="${name}"/>
+ <input type="submit" value="Update Properties" class="float_button"/>
+ <table id="node_tattr">
+ <tr>
+ <td class="node_tattr_caption">
+ Number of votes
+ </td><td class="node_tattr_input">
+ <input type="text" name="votes" py:attrs="{'value': node_data.getVotes()}"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+
+ </div>
+ </div>
+
<!--! DETAILS - services section. -->
<div class="details_section">
<h4>Services</h4>
@@ -333,7 +355,7 @@
<input type="Submit" value="Submit" class="button formsubmit blue" />
<input type="button" class="button formsubmit silver" value="Cancel"
onclick="$('#edit_fencedev_dialog_${instance_id}').dialog('close')" />
- </div>
+ </div>
</form>
</div>
</div>
@@ -437,7 +459,7 @@
<input type="Submit" value="Submit" class="button formsubmit blue" />
<input type="button" class="button formsubmit silver" value="Cancel"
onclick="$('#create_fencedev_dialog').dialog('close')" />
- </div>
+ </div>
</form>
</div>
</div>
@@ -450,7 +472,7 @@
<input type="Submit" value="Submit" class="button formsubmit blue" />
<input type="button" class="button formsubmit silver" value="Cancel"
onclick="$('#create_fencemethod_dialog').dialog('close')" />
- </div>
+ </div>
</form>
</div>
</div>
13 years, 8 months
[luci] Fix rhbz#624819: incompatibility with TG 2.1
by Jan Pokorný
commit ec1c9f46c194aa21d75c8e30aff17d023e1bb545
Author: Jan Pokorny <jpokorny(a)redhat.com>
Date: Tue Aug 17 22:37:18 2010 +0200
Fix rhbz#624819: incompatibility with TG 2.1
Mainly renaming 'default' method to 'index'.
luci/controllers/cluster.py | 4 ++--
luci/controllers/root.py | 1 +
luci/lib/app_strings.py | 38 +++++++++++++++++++-------------------
luci/templates/master.html | 2 +-
4 files changed, 23 insertions(+), 22 deletions(-)
---
diff --git a/luci/controllers/cluster.py b/luci/controllers/cluster.py
index e1c14bd..86bc1e0 100644
--- a/luci/controllers/cluster.py
+++ b/luci/controllers/cluster.py
@@ -90,7 +90,7 @@ class IndividualClusterController(BaseController):
tmpl_context.cluster = self
@expose("luci.templates.node")
- def default(self):
+ def index(self):
db = get_cluster_db_obj(self.name)
return dict(page='nodes', name=self.nodename, base_url='/nodes', nodes=db.nodes)
@@ -790,7 +790,7 @@ class IndividualNodeController(BaseController):
tmpl_context.show_sidebar = True
@expose("luci.templates.node")
- def default(self):
+ def index(self):
db = get_cluster_db_obj(self.name)
return dict(page='nodes', name=self.nodename, base_url='/nodes', nodes=db.nodes)
diff --git a/luci/controllers/root.py b/luci/controllers/root.py
index 02e69db..1d11cd4 100644
--- a/luci/controllers/root.py
+++ b/luci/controllers/root.py
@@ -67,6 +67,7 @@ class RootController(BaseController):
def homebase(self, homebasepage='homebasepage', **args):
tmpl_context.show_sidebar = True
tmpl_context.homebase = True
+ tmpl_context.cluster = []
return dict(page='homebase', homebasepage=homebasepage, args=args,
base_url='/cluster')
diff --git a/luci/lib/app_strings.py b/luci/lib/app_strings.py
index daa9de3..fde70e0 100644
--- a/luci/lib/app_strings.py
+++ b/luci/lib/app_strings.py
@@ -8,7 +8,7 @@
# -*- coding: utf-8 -*-
"""Separated encapsulations of common strings and short sentences."""
-from pylons.i18n import ugettext as _
+from pylons.i18n import lazy_ugettext as l_
# Imported, but not in module's header: tg (tmpl_context)
__all__ = ['Title', 'FlashMsg']
@@ -50,26 +50,26 @@ class Title:
# is used as a key for storing/retrieving such string parameters
# to separated dict respectively.
- CLUSTERS = _('clusters')
- CERTAIN_CLUSTER = _('cluster {cluster}'), 'cluster'
+ CLUSTERS = l_('clusters')
+ CERTAIN_CLUSTER = l_('cluster {cluster}'), 'cluster'
- CLUSTER_CREATE = _('create cluster')
- CLUSTER_ADD_EXISTING = _('add an existing cluster')
+ CLUSTER_CREATE = l_('create cluster')
+ CLUSTER_ADD_EXISTING = l_('add an existing cluster')
- GLOBAL_RES = _('resources')
- CERTAIN_GLOBAL_RES = _('resource {global_res}'), 'global_res'
+ GLOBAL_RES = l_('resources')
+ CERTAIN_GLOBAL_RES = l_('resource {global_res}'), 'global_res'
- NODES = _('nodes')
- CERTAIN_NODE = _('node {node}'), 'node'
+ NODES = l_('nodes')
+ CERTAIN_NODE = l_('node {node}'), 'node'
- SERVICES = _('services')
- CERTAIN_SERVICE = _('service {service}'), 'service'
+ SERVICES = l_('services')
+ CERTAIN_SERVICE = l_('service {service}'), 'service'
- FAILOVERS = _('failovers')
- CERTAIN_FAILOVER = _('failover {failover}'), 'failover'
+ FAILOVERS = l_('failovers')
+ CERTAIN_FAILOVER = l_('failover {failover}'), 'failover'
- FENCES = _('fences')
- CERTAIN_FENCE = _('fence {fence}'), 'fence'
+ FENCES = l_('fences')
+ CERTAIN_FENCE = l_('fence {fence}'), 'fence'
class FlashMsg:
@@ -81,11 +81,11 @@ class FlashMsg:
# Pairs of message and the message status to be used by tg.flash method.
# Connected with
- BAD_COMMAND_REQUEST = _('Bad command request.'), STYLE_WARNING
- INTERNAL_ERROR = _('Internal error.'), STYLE_ERROR
- NOTHING_CHOSEN = _('Nothing was chosen.'), STYLE_WARNING
+ BAD_COMMAND_REQUEST = l_('Bad command request.'), STYLE_WARNING
+ INTERNAL_ERROR = l_('Internal error.'), STYLE_ERROR
+ NOTHING_CHOSEN = l_('Nothing was chosen.'), STYLE_WARNING
# Connected with decorators.
- UNSUPPORTED_METHOD = _('%s method not supported in this context.'), STYLE_ERROR
+ UNSUPPORTED_METHOD = l_('%s method not supported in this context.'), STYLE_ERROR
diff --git a/luci/templates/master.html b/luci/templates/master.html
index eccbbab..5b37d77 100644
--- a/luci/templates/master.html
+++ b/luci/templates/master.html
@@ -43,7 +43,7 @@
<div py:if="flash" py:content="XML(flash)" />
</py:with>
- <py:if test="'show_sidebar' in dir(tmpl_context)">
+ <py:if test="'show_sidebar' in dir(tmpl_context) and tmpl_context.show_sidebar">
<xi:include href="mainmenu.html" />
</py:if>
13 years, 8 months
[luci] Re: Fix rhbz#622562: forgotten files(forgotten -a)
by Jan Pokorný
commit 847508ae4483685d3eb59ed47433c02562c6bf0f
Author: Jan Pokorny <jpokorny(a)redhat.com>
Date: Fri Aug 13 19:08:08 2010 +0200
Re: Fix rhbz#622562: forgotten files(forgotten -a)
luci/controllers/cluster.py | 69 +++++++++++++++++-
luci/lib/ClusterConf/Device.py | 8 ++
luci/lib/ClusterConf/ModelBuilder.py | 2 +
luci/lib/ClusterConf/TagObject.py | 17 ++++-
luci/templates/fence_instances.html | 117 ++++++++++++++++++++----------
luci/templates/node.html | 8 ++-
luci/widget_validators/validate_fence.py | 38 ++++++++--
7 files changed, 208 insertions(+), 51 deletions(-)
---
diff --git a/luci/controllers/cluster.py b/luci/controllers/cluster.py
index 62adfa2..e1c14bd 100644
--- a/luci/controllers/cluster.py
+++ b/luci/controllers/cluster.py
@@ -24,6 +24,7 @@ from luci.widget_validators.validate_create_cluster_form import validate_create_
from luci.widget_validators.validate_fence import validateNewFenceDevice, validateFenceDevice
from luci.widget_validators.validate_resource import validate_clusvc_form, validate_resource_form
from luci.lib.ClusterConf.Method import Method
+from luci.lib.ClusterConf.Unfence import Unfence
from luci.widget_validators.validate_fence import validate_fenceinstance
import logging
@@ -121,6 +122,25 @@ class IndividualClusterController(BaseController):
return self.version
+ @staticmethod
+ def remove_fence_instance(node, method, instance):
+ """Macro-like function to remove fence instance from given node and its fence method."""
+ for child in node.getChildren():
+ if child.getTagName() == 'unfence':
+ unfence = child
+ for child_device in unfence.getChildren():
+ # Try to find existing unfence device that mirrored fence device instance
+ # to be removed and remove it, too.
+ if len(set(instance.getAttributes().items()).difference(child_device.getAttributes().items())) == 0:
+ unfence.removeChild(child_device)
+ if len(unfence.getChildren()) == 0:
+ # Remove the whole 'unfence' section from within 'node' section
+ # it is empty.
+ node.removeChild(unfence)
+ break
+ break
+ method.removeChild(instance)
+
@expose("luci.templates.node")
def nodes(self):
db = get_cluster_db_obj(self.name)
@@ -146,6 +166,8 @@ class IndividualClusterController(BaseController):
methodname = kw.get("method_to_remove")
for child in node.getFenceNode().getChildren():
if child.getName() == methodname:
+ for child_device in child.getChildren():
+ self.remove_fence_instance(node, child, child_device)
node.getFenceNode().removeChild(child)
break
self.model.setModified(True)
@@ -157,7 +179,7 @@ class IndividualClusterController(BaseController):
methodname = kw.get("fenceinst_to_remove_method")
for child in node.getFenceNode().getChildren():
if child.getName() == methodname:
- child.removeChild(child.children[int(fenceinst)-1])
+ self.remove_fence_instance(node, child, child.children[int(fenceinst)-1])
self.model.setModified(True)
rh.update_cluster_conf(self.model)
@@ -204,8 +226,20 @@ class IndividualClusterController(BaseController):
parent_fencedev = kw['parent_fencedev'].replace('fd_', '', 1)
- retcode, retobj = validate_fenceinstance(parent_fencedev, kw['fence_type'], **kw)
+ retcode, retobj, retunfence = validate_fenceinstance(parent_fencedev, kw['fence_type'], **kw)
if retcode is True:
+ # Add unfence section if requested.
+ if retunfence is not None:
+ unfence = None
+ for child in node.getChildren():
+ if child.getTagName() == 'unfence':
+ unfence = child
+ break
+ if unfence is None:
+ unfence = Unfence()
+ node.addChild(unfence)
+ unfence.addChild(retunfence)
+ # ---
fence_method.addChild(retobj)
if len(levels) == 0:
fence_node = node.getFenceNode()
@@ -224,8 +258,37 @@ class IndividualClusterController(BaseController):
(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 = validate_fenceinstance(kw["fencedev"], kw['fence_type'], **kw)
+ retcode, retobj, retunfence = validate_fenceinstance(kw["fencedev"], kw['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)]
+ unfence = None
+ unfence_handled = False
+ for child in node.getChildren():
+ if child.getTagName() == 'unfence':
+ unfence = child
+ for child_device in unfence.getChildren():
+ # Try to find existing unfence device that mirrored old fence device instance
+ # (i.e. before the change, with original values of attributes) and remove it
+ # or replace it with current attributes (i.e. after the change).
+ if len(set(old_device.getAttributes().items()).difference(child_device.getAttributes().items())) == 0:
+ if (retunfence is None):
+ unfence.removeChild(child_device)
+ if len(unfence.getChildren()) == 0:
+ # Remove the whole 'unfence' section from within 'node' section
+ # it is empty.
+ node.removeChild(unfence)
+ else:
+ unfence.replaceChild(child_device, retunfence)
+ unfence_handled = True
+ break
+ break
+ if not unfence_handled and retunfence is not None:
+ if unfence is None:
+ unfence = Unfence()
+ node.addChild(unfence)
+ unfence.addChild(retunfence)
+ # ---
node.getFenceNode().children[int(method_num)].children[int(fence_instance_id)] = retobj
self.model.setModified(True)
rh.update_cluster_conf(self.model)
diff --git a/luci/lib/ClusterConf/Device.py b/luci/lib/ClusterConf/Device.py
index 57556f3..9f92f62 100644
--- a/luci/lib/ClusterConf/Device.py
+++ b/luci/lib/ClusterConf/Device.py
@@ -35,3 +35,11 @@ class Device(TagObject):
if name == OPTION:
self.has_native_option_set = True
self.attr_hash[name] = value
+
+ def clone(self):
+ """Creates a shallow copy of itself."""
+ ret = TagObject.clone(self)
+ ret.agent_type = self.agent_type
+ ret.has_native_option_set = self.has_native_option_set
+ ret.pretty_fence_names = self.pretty_fence_names
+ return ret
diff --git a/luci/lib/ClusterConf/ModelBuilder.py b/luci/lib/ClusterConf/ModelBuilder.py
index e7cdbb6..2d0a73a 100644
--- a/luci/lib/ClusterConf/ModelBuilder.py
+++ b/luci/lib/ClusterConf/ModelBuilder.py
@@ -11,6 +11,7 @@ from Cluster import Cluster
from ClusterNode import ClusterNode
from ClusterNodes import ClusterNodes
from Fence import Fence
+from Unfence import Unfence
from FenceDevice import FenceDevice
from FenceDevices import FenceDevices
from Method import Method
@@ -64,6 +65,7 @@ TAGNAMES = { 'cluster': Cluster,
'clusternode': ClusterNode,
'altname': Altname,
'fence': Fence,
+ 'unfence': Unfence,
'fencedevice': FenceDevice,
'fencedevices': FenceDevices,
'method': Method,
diff --git a/luci/lib/ClusterConf/TagObject.py b/luci/lib/ClusterConf/TagObject.py
index 0087dbc..5872f4a 100644
--- a/luci/lib/ClusterConf/TagObject.py
+++ b/luci/lib/ClusterConf/TagObject.py
@@ -56,7 +56,8 @@ class TagObject:
return self.attr_hash.get(key)
def getChildren(self):
- return self.children
+ """Returns copy of children's list."""
+ return self.children[:]
def getName(self):
try:
@@ -78,3 +79,17 @@ class TagObject:
if child is None:
continue
child.searchTree(objlist, tagtype)
+
+ def replaceChild(self, oldchild, newchild):
+ """Looks up oldchild and replace it with newchild."""
+ idx = self.children.index(oldchild)
+ self.children[idx] = newchild
+
+
+ def clone(self):
+ """Creates a shallow copy of itself."""
+ ret = self.__class__ ()
+ ret.TAG_NAME = self.TAG_NAME
+ ret.attr_hash = self.attr_hash.copy()
+ ret.children = self.children
+ return ret
diff --git a/luci/templates/fence_instances.html b/luci/templates/fence_instances.html
index 41c8270..ede58ba 100644
--- a/luci/templates/fence_instances.html
+++ b/luci/templates/fence_instances.html
@@ -2,7 +2,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip="">
-<div py:def="fence_apc_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_apc_instance"
+<div py:def="fence_apc_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_apc_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -56,7 +56,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_egenera_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_egenera_instance"
+<div py:def="fence_egenera_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_egenera_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -94,7 +94,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_lpar_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_lpar_instance"
+<div py:def="fence_lpar_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_lpar_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -133,7 +133,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_vmware_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_vmware_instance"
+<div py:def="fence_vmware_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_vmware_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -180,7 +180,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_wti_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_wti_instance"
+<div py:def="fence_wti_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_wti_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -227,7 +227,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_brocade_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_brocade_instance"
+<div py:def="fence_brocade_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_brocade_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -237,6 +237,15 @@
py:attrs="cur_fence_inst and {'value': cur_fence_inst.getAttribute('port')}"/>
</td>
</tr>
+ <tr>
+ <td>Unfencing</td>
+ <td>
+ <input type="checkbox" class="checkbox" name="unfencing"
+ py:attrs="(not cur_fence_inst or kw.get('unfencing', True)) and {'checked': 'checked'}"/>
+ <label class="choice">Enable</label>
+ <input type="hidden" name="unfence_action" value="enable" />
+ </td>
+ </tr>
<tr><td colspan="2">
<div>
<input type="button" name="remove_fence" value="Remove this instance"
@@ -251,7 +260,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_vixel_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_vixel_instance"
+<div py:def="fence_vixel_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_vixel_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -275,7 +284,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_sanbox2_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_sanbox2_instance"
+<div py:def="fence_sanbox2_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_sanbox2_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -285,6 +294,15 @@
py:attrs="cur_fence_inst and {'value': cur_fence_inst.getAttribute('port')}"/>
</td>
</tr>
+ <tr>
+ <td>Unfencing</td>
+ <td>
+ <input type="checkbox" class="checkbox" name="unfencing"
+ py:attrs="(not cur_fence_inst or kw.get('unfencing', True)) and {'checked': 'checked'}"/>
+ <label class="choice">Enable</label>
+ <input type="hidden" name="unfence_action" value="enable" />
+ </td>
+ </tr>
<tr><td colspan="2">
<div>
<input type="button" name="remove_fence" value="Remove this instance"
@@ -299,7 +317,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_mcdata_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_mcdata_instance"
+<div py:def="fence_mcdata_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_mcdata_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -309,6 +327,15 @@
py:attrs="cur_fence_inst and {'value': cur_fence_inst.getAttribute('port')}"/>
</td>
</tr>
+ <tr>
+ <td>Unfencing</td>
+ <td>
+ <input type="checkbox" class="checkbox" name="unfencing"
+ py:attrs="(not cur_fence_inst or kw.get('unfencing', True)) and {'checked': 'checked'}"/>
+ <label class="choice">Enable</label>
+ <input type="hidden" name="unfence_action" value="enable" />
+ </td>
+ </tr>
<tr><td colspan="2">
<div>
<input type="button" name="remove_fence" value="Remove this instance"
@@ -323,7 +350,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_gnbd_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_gnbd_instance"
+<div py:def="fence_gnbd_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_gnbd_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -347,7 +374,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_bullpap_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_bullpap_instance"
+<div py:def="fence_bullpap_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_bullpap_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -371,7 +398,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_virt_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_virt_instance"
+<div py:def="fence_virt_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_virt_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -395,7 +422,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_xvm_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_xvm_instance"
+<div py:def="fence_xvm_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_xvm_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -419,7 +446,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_bladecenter_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_bladecenter_instance"
+<div py:def="fence_bladecenter_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_bladecenter_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -466,7 +493,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_rackswitch_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_rackswitch_instance"
+<div py:def="fence_rackswitch_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_rackswitch_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -490,7 +517,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_ldom_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_ldom_instance"
+<div py:def="fence_ldom_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_ldom_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -537,7 +564,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_cisco_mds_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_cisco_mds_instance"
+<div py:def="fence_cisco_mds_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_cisco_mds_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -561,7 +588,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_eps_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_eps_instance"
+<div py:def="fence_eps_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_eps_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -585,7 +612,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_ibmblade_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_ibmblade_instance"
+<div py:def="fence_ibmblade_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_ibmblade_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -609,7 +636,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_ifmib_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_ifmib_instance"
+<div py:def="fence_ifmib_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_ifmib_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -633,7 +660,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_intelmodular_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_intelmodular_instance"
+<div py:def="fence_intelmodular_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_intelmodular_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -657,7 +684,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_apc_snmp_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_apc_snmp_instance"
+<div py:def="fence_apc_snmp_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_apc_snmp_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<table class="detailstable">
<tr>
@@ -681,7 +708,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_drac_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_drac_instance"
+<div py:def="fence_drac_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_drac_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -690,7 +717,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_drac5_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_drac5_instance"
+<div py:def="fence_drac5_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_drac5_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -699,7 +726,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_ilo_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_ilo_instance"
+<div py:def="fence_ilo_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_ilo_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -708,7 +735,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_ilo_mp_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_ilo_mp_instance"
+<div py:def="fence_ilo_mp_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_ilo_mp_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -717,7 +744,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_rsa_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_rsa_instance"
+<div py:def="fence_rsa_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_rsa_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -726,7 +753,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_ipmilan_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_ipmilan_instance"
+<div py:def="fence_ipmilan_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_ipmilan_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -735,7 +762,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_alom_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_alom_instance"
+<div py:def="fence_alom_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_alom_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -744,7 +771,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_cpint_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_cpint_instance"
+<div py:def="fence_cpint_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_cpint_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -753,7 +780,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_rps10_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_rps10_instance"
+<div py:def="fence_rps10_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_rps10_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -762,7 +789,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_rsb_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_rsb_instance"
+<div py:def="fence_rsb_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_rsb_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -771,7 +798,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_xcat_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_xcat_instance"
+<div py:def="fence_xcat_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_xcat_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -780,7 +807,7 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_zvm_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_zvm_instance"
+<div py:def="fence_zvm_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_zvm_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_scsi" />
@@ -789,16 +816,32 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_scsi_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_scsi_instance"
+<div py:def="fence_scsi_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_scsi_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
-
+ <table class="detailstable">
+ <tr>
+ <td>Unfencing</td>
+ <td>
+ <input type="checkbox" class="checkbox" name="unfencing"
+ py:attrs="(not cur_fence_inst or kw.get('unfencing', True)) and {'checked': 'checked'}"/>
+ <label class="choice">Enable</label>
+ <input type="hidden" name="unfence_action" value="on" />
+ </td>
+ </tr>
+ <tr><td colspan="2">
+ <div>
+ <input type="button" name="remove_fence" value="Remove this instance"
+ py:attrs="fi_id is not None and {'onclick': '$(\'#%s\').remove()' % fi_id} or {}"/>
+ </div>
+ </td></tr>
+ </table>
<input type="hidden" name="fence_type" value="fence_scsi" />
<input type="hidden" name="fence_instance" value="1" />
<input type="hidden" name="parent_fencedev"
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
-<div py:def="fence_unknown_instance(cur_fence_inst, cur_fence_dev_id, fi_id)" id="fence_unknown_instance"
+<div py:def="fence_unknown_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_unknown_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
<input type="hidden" name="fence_type" value="fence_unknown" />
diff --git a/luci/templates/node.html b/luci/templates/node.html
index 546774d..5956048 100644
--- a/luci/templates/node.html
+++ b/luci/templates/node.html
@@ -296,7 +296,7 @@
<th>Type/Values</th>
<th></th>
</tr>
- <py:for each="instancenum,(fin,fd) in enumerate(instances)">
+ <py:for each="instancenum,(fin,fd,unfencing) in enumerate(instances)">
<?python
agent_type = fd.getAgentType()
agent_name = fd.getPrettyName()
@@ -327,7 +327,7 @@
inst_fn = eval('fence_unknown_instance')
inst_fn(fin, instance_id, None)
?>
- ${inst_fn(fin, cur_dev_id, '%s_%s' % (cur_dev_id, cur_dev_id))}
+ ${inst_fn(fin, cur_dev_id, '%s_%s' % (cur_dev_id, cur_dev_id), unfencing=unfencing)}
</div>
<div class="row">
<input type="Submit" value="Submit" class="button formsubmit blue" />
@@ -365,6 +365,10 @@
</td>
</py:if>
</tr>
+ <tr py:if="unfencing == True">
+ <td></td>
+ <td>unfencing enabled</td>
+ </tr>
</py:for>
<tr>
<td colspan="3">
diff --git a/luci/widget_validators/validate_fence.py b/luci/widget_validators/validate_fence.py
index ebf24d7..f9339e1 100644
--- a/luci/widget_validators/validate_fence.py
+++ b/luci/widget_validators/validate_fence.py
@@ -918,6 +918,9 @@ def validate_fenceinstance(parent_name, fence_agent, **kw):
fenceinst.addAttribute('name', parent_name)
fenceinst.setAgentType(fence_agent)
+ unfence = None
+
+ # XXX: Remove following 4 lines?
if kw.has_key('option'):
option = kw.get('option').strip()
if option:
@@ -926,12 +929,16 @@ def validate_fenceinstance(parent_name, fence_agent, **kw):
try:
ret = FI_VALIDATE[fence_agent](fenceinst, parent_name, **kw)
if len(ret) > 0:
- return (False, ret)
+ return (False, ret, None)
except Exception, e:
log.exception('Error validating fence %s instance of %s' % (fence_agent, parent_name))
- return (False, [ FI_NEW_FAIL % fence_agent ])
+ return (False, [ FI_NEW_FAIL % fence_agent ], )
- return (True, fenceinst)
+ if kw.has_key('unfencing'):
+ # If unfencing required, create and return it's object.
+ unfence = fenceinst.clone()
+ unfence.addAttribute('action', kw['unfence_action'])
+ return (True, fenceinst, unfence)
def getDeviceForInstance(fds, name):
for fd in fds:
@@ -1039,9 +1046,11 @@ def get_fence_level_info(fence_level, node, fds, major_num, minor_num):
cur_shared.append(shared_struct)
return (cur_level, cur_shared, major_num, minor_num)
-# Return a list of lists containing the level/method and fence instances for
-# that level
def getFenceInfo(model, nodename):
+ """Return a list of lists containing the level/method and fence instances for that level.
+
+ """
+
fence_map = []
try:
@@ -1060,8 +1069,21 @@ def getFenceInfo(model, nodename):
fence_map_level = [0,0]
fence_map_level[0] = level
fence_map_level[1] = []
- instances = level.getChildren()
- for instance in instances:
- fence_map_level[1].append([instance,getDeviceForInstance(fds,instance.getName().strip())])
+
+ for instance in level.getChildren():
+ # Lookup, whether the unfencing was set and add a flag appropriately.
+ unfencing_flag = False
+ for child in node.getChildren():
+ if child.getTagName() == 'unfence':
+ unfence = child
+ for child_device in unfence.getChildren():
+ # Try to find existing unfence device that mirrored fence device instance
+ # to be removed and remove it, too.
+ if len(set(instance.getAttributes().items()).difference(child_device.getAttributes().items())) == 0:
+ unfencing_flag = True
+ break
+ break
+
+ fence_map_level[1].append([instance,getDeviceForInstance(fds,instance.getName().strip()),unfencing_flag])
fence_map.append(fence_map_level)
return fence_map
13 years, 8 months
[luci] Fix rhbz#622562: support for unfencing config.
by Jan Pokorný
commit ca226dabc8d51073322b44971b14c3ecdc94a686
Author: Jan Pokorny <jpokorny(a)redhat.com>
Date: Fri Aug 13 19:04:07 2010 +0200
Fix rhbz#622562: support for unfencing config.
Following (storage) fence devices are affected, listed together with
appropriate action for unfencing:
* brocade - enable
* mcdata - enable
* scsi - on
* sanbox2 - enable
luci/lib/ClusterConf/Unfence.py | 15 +++++++++++++++
1 files changed, 15 insertions(+), 0 deletions(-)
---
diff --git a/luci/lib/ClusterConf/Unfence.py b/luci/lib/ClusterConf/Unfence.py
new file mode 100644
index 0000000..411e5a2
--- /dev/null
+++ b/luci/lib/ClusterConf/Unfence.py
@@ -0,0 +1,15 @@
+# Copyright (C) 2006-2009 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.
+
+from TagObject import TagObject
+
+TAG_NAME = "unfence"
+
+class Unfence(TagObject):
+ def __init__(self):
+ TagObject.__init__(self)
+ self.TAG_NAME = TAG_NAME
13 years, 8 months
[luci] Bump the minor version number and update spec file for new upstream
by Ryan McCabe
commit 6d962b24b5a50256c612d06109fca0e9a4c77bb7
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Sun Aug 8 22:25:33 2010 -0400
Bump the minor version number and update spec file for new upstream
version 0.22.4.
luci.spec | 12 +++++++++++-
setup.py | 2 +-
2 files changed, 12 insertions(+), 2 deletions(-)
---
diff --git a/luci.spec b/luci.spec
index 4d92ac3..d82df03 100644
--- a/luci.spec
+++ b/luci.spec
@@ -3,7 +3,7 @@
%{!?pyver: %define pyver %(%{__python} -c "import sys ; print sys.version[:3]")}
Name: luci
-Version: 0.22.3
+Version: 0.22.4
Release: 1%{?dist}
Summary: Web-based high availability administration application
Group: Applications/System
@@ -81,6 +81,16 @@ fi
exit 0
%changelog
+* Sun Aug 08 2010 Ryan McCabe <rmccabe(a)redhat.com> - 0.22.4-1
+- Version 0.22.4
+- Remove extra debugging logging from the fix for bz619220
+- Fix bz614130 (implement tomcat6 resource agent)
+- Fix bz618578 (ip resource should have netmask field)
+- Fix bz615926 (luci does not handle qdisk / cman config correctly)
+- Fix bz619220 (Luci does extra queries which slows down page load)
+- Fix bz619652 (luci sometimes prints a traceback when deleting multiple nodes at the same time)
+- Fix bz619641 (luci init script prints a python traceback when status is queried by a non-root user)
+
* Fri Jul 30 2010 Ryan McCabe <rmccabe(a)redhat.com> - 0.22.3-1
- Version 0.22.3
diff --git a/setup.py b/setup.py
index 8bbc933..d22b2d1 100644
--- a/setup.py
+++ b/setup.py
@@ -8,7 +8,7 @@ except ImportError:
setup(
name='luci',
- version='0.22.3',
+ version='0.22.4',
license='GPLv2',
description='Web-based cluster administration application',
author='',
13 years, 9 months
[luci] Re: Fix rhbz#620377 - another fine-tuning
by Jan Pokorný
commit 07c8cd29234f474e853cf6d4f56e746ef57da31a
Author: Jan Pokorny <jpokorny(a)redhat.com>
Date: Fri Aug 6 20:23:26 2010 +0200
Re: Fix rhbz#620377 - another fine-tuning
luci/templates/resource_list.html | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/luci/templates/resource_list.html b/luci/templates/resource_list.html
index b8f3ec4..d769fcb 100644
--- a/luci/templates/resource_list.html
+++ b/luci/templates/resource_list.html
@@ -1487,7 +1487,7 @@ ${vm_resource(None,None,None,0)}
py:attrs="{'onchange': model and svc_onchange_fn or res_onchange_fn, 'id': parentid and '%s_resource_selector' % parentid or 'resource_selector'}">
<py:if test="model" py:with="global_res = model.getResources()">
<py:if test="len(global_res) != 0">
- <option>-- Global resources --</option>
+ <option disabled="disabled">-- Global resources --</option>
<option py:for="res in global_res"
py:with="cur_res_name = res.getName();
cur_res_id = 'global_res_%s' % cur_res_name"
13 years, 9 months
[luci] Re: Fix rhbz#620377 - some items not selectable
by Jan Pokorný
commit 7e1949639ea8ff64e1d43929054c5d68d89a66c4
Author: Jan Pokorny <jpokorny(a)redhat.com>
Date: Fri Aug 6 20:12:15 2010 +0200
Re: Fix rhbz#620377 - some items not selectable
luci/templates/fence_devices.html | 4 ++--
luci/templates/resource_list.html | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
---
diff --git a/luci/templates/fence_devices.html b/luci/templates/fence_devices.html
index 0922e1a..0eb589c 100644
--- a/luci/templates/fence_devices.html
+++ b/luci/templates/fence_devices.html
@@ -2744,7 +2744,7 @@ ${fence_unknown(None,0)}
<py:if test="model and len(model.getFenceDevices()) != 0">
<select name="select_div"
onchange="add_fenceinst('${cont_id}',fencedevicetype[this.options[this.selectedIndex].value],this.options[this.selectedIndex].value);">
- <option>-- Select a fence device --</option>
+ <option selected="selected" disabled="disabled">-- Select a fence device --</option>
<option disabled="disabled">Existing fence devices</option>
<py:for each="fencedev in model.getFenceDevices()">
<script type="text/javascript">
@@ -2761,7 +2761,7 @@ ${fence_unknown(None,0)}
<select name="select_div"
onchange="swap_fence_form(this.options[this.selectedIndex].value, '${cont_id}')"
py:with="cluster_version = tmpl_context.cluster.get_version()" >
- <option>-- Select a fence device --</option>
+ <option selected="selected" disabled="disabled">-- Select a fence device --</option>
<option name="fence_apc" value="fence_apc">APC Power Switch</option>
<option name="fence_apc_snmp" value="fence_apc_snmp">APC Power Switch (SNMP interface)</option>
<option py:if="cluster_version == 2" name="fence_brocade" value="fence_brocade">Brocade Fabric Switch</option>
diff --git a/luci/templates/resource_list.html b/luci/templates/resource_list.html
index 03071f1..b8f3ec4 100644
--- a/luci/templates/resource_list.html
+++ b/luci/templates/resource_list.html
@@ -1496,7 +1496,7 @@ ${vm_resource(None,None,None,0)}
</py:if>
</py:if>
- <option>-- Select a resource type --</option>
+ <option selected="selected" disabled="disabled">-- Select a resource type --</option>
<option name="apache_resource" value="apache_resource">Apache</option>
<option name="fs_resource" value="fs_resource">Filesystem</option>
<py:choose test="cluster_version">
13 years, 9 months