[luci] Update to new upstream release and steal fixes from upstream git

Fabio M. Di Nitto fabbione at fedoraproject.org
Thu Aug 19 13:52:50 UTC 2010


commit f3ea824cfa1a4bc2be0ecb2e934f2238c6b619f9
Author: Fabio M. Di Nitto <fdinitto at redhat.com>
Date:   Thu Aug 19 15:52:28 2010 +0200

    Update to new upstream release and steal fixes from upstream git
    
    Signed-off-by: Fabio M. Di Nitto <fdinitto at redhat.com>

 .gitignore            |    2 +
 luci.spec             |  189 ++++++++++-
 sources               |    3 +-
 stolen_from_git.patch |  854 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1033 insertions(+), 15 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index e69de29..819a1c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/luci-0.22.4.tar.bz2
+/logo.png
diff --git a/luci.spec b/luci.spec
index 8c59e1a..019a0c3 100644
--- a/luci.spec
+++ b/luci.spec
@@ -1,37 +1,47 @@
 %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
+%{!?python_sitelib_arch: %define python_sitelib_arch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
 %{!?pyver: %define pyver %(%{__python} -c "import sys ; print sys.version[:3]")}
 
+%global alphatag 0.b9faf868074git
+
 Name: luci
-Version: 0.21.0
-Release: 6%{?dist}
-Summary: Web-based cluster administration application
+Version: 0.22.4
+Release: 1%{?alphatag:.%{alphatag}}%{?dist}
+Summary: Web-based high availability administration application
 Group: Applications/System
 License: GPLv2
 URL: http://sources.redhat.com/cluster/conga
-Source0: http://people.redhat.com/rmccabe/luci/luci-0.21.0.tar.bz2
+Source0: http://people.redhat.com/rmccabe/luci/luci-0.22.4.tar.bz2
+Source1: logo.png
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-BuildArch: noarch
-BuildRequires: python-devel python-setuptools python-paste python-paste-script
-Requires: TurboGears2 python-tw-jquery python-repoze-what-quickstart python-catwalk python-tg-devtools
+BuildRequires: python-devel python-setuptools python-paste python-paste-script cyrus-sasl-devel
+Requires: TurboGears2 openssl python-repoze-who-friendlyform python-tw-forms
+Requires: python-paste >= 1.7.2-5.el6
 Requires(post): chkconfig initscripts
 Requires(preun): chkconfig initscripts
 Requires(postun): initscripts
 
+Patch0: stolen_from_git.patch
+
 %description
-Luci is a web-based cluster administration application built on the
+Luci is a web-based high availability administration application built on the
 TurboGears 2 framework.
 
 %prep
 %setup -q
+cp %{_sourcedir}/logo.png %{_builddir}/luci-0.22.4/luci/public/images
+%patch0 -p1 -b .stolen_from_git
 
 %build
 python setup.py build
 
 %install
 rm -rf %{buildroot}
+mkdir -p %{buildroot}/var/log/luci
 python setup.py install --skip-build --root %{buildroot}
 cd init.d && make DESTDIR=%{buildroot} install;cd ..
 cd config && make DESTDIR=%{buildroot} install;cd ..
+cd lucipam && python setup.py install --root %{buildroot};  cd ..
 
 %clean
 rm -rf %{buildroot}
@@ -40,17 +50,23 @@ rm -rf %{buildroot}
 %defattr(-,root,root,-)
 %doc README.txt COPYING
 %{python_sitelib}/%{name}-%{version}-py%{pyver}.egg-info/
-%{python_sitelib}/luci
+%{python_sitelib}/%{name}/
+%{python_sitelib_arch}/LuciPAM-1.0-py%{pyver}.egg-info
+%{python_sitelib_arch}/lucipam.so
 
+%config(noreplace)      /etc/pam.d/luci
 %config(noreplace)      %{_localstatedir}/lib/luci/etc/luci.ini
 %attr(0600,luci,luci)   %{_localstatedir}/lib/luci/etc/luci.ini
+%config(noreplace)      %{_localstatedir}/lib/luci/etc/cacert.config
+%attr(0600,luci,luci)   %{_localstatedir}/lib/luci/etc/cacert.config
 %attr(0750,luci,luci)   %{_localstatedir}/lib/luci
 %config(noreplace)      %{_sysconfdir}/rc.d/init.d/luci
-
+%attr(750, luci, luci)  %dir /var/log/luci
 
 %pre
-getent group luci >/dev/null || groupadd -r luci
-getent passwd luci >/dev/null || useradd -r -g luci -d /var/lib/luci -s /sbin/nologin -c "luci user" luci
+/usr/sbin/groupadd -g 141 luci 2> /dev/null
+/usr/sbin/useradd -u 141 -g 141 -d /var/lib/luci -s /sbin/nologin -r \
+        -c "luci user" luci 2> /dev/null
 exit 0
 
 %post
@@ -71,8 +87,153 @@ fi
 exit 0
 
 %changelog
-* Sun Aug 01 2010 Orcan Ogetbil <oget[dot]fedora[at]gmail[dot]com> - 0.21-0-6
-- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild
+* Thu Aug 19 2010 Fabio M. Di Nitto <fdinitto at redhat.com> - 0.22.4-1.0.b9faf868074git
+- New upstream release (0.22.4)
+- Steal fixes from upstream git up to b9faf868074git
+  Fix bz622562 (add support for unfencing)
+  Fix bz624819 (add compatibility with TG2.1)
+- Update spec file to support alphatag
+
+* Tue Aug 03 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-13
+- Remove extra debugging logging from the fix for bz619220
+- Fix bz614130 (implement tomcat6 resource agent)
+- Fix bz618578 (ip resource should have netmask field)
+
+* Tue Aug 03 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-12
+- 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)
+
+* Thu Jul 29 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-11
+- Fix bz614433 (cannot configure ipport for fence agents)
+- Fix bz617575 (Unclear options when configuring a cluster)
+- Fix bz617591 (Some fields when adding an IP address are unclear)
+- Fix bz617602 (Fields in "Fence Daemon Properties" have no units)
+- Fix bz618577 (wrong message displayed when adding ip resource)
+- Fix bz619220 (Luci does extra queries which slows down page load)
+
+* Tue Jul 26 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-10
+- Additional fixes for bz600027 (Fix cluster service creation/configuration UX issues)
+- Additional fixes for bz600055 ("cluster busy" dialog does not work)
+- Fix bz618424 (Can't remove nodes in node add dialog or create cluster dialog)
+- Fix bz616382 (luci db error removing a node from a cluster)
+- Fix bz613871 (luci should not give ungraceful error messages when encountering fence devices that it does not recognize/support)
+
+* Mon Jul 26 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-9
+- Fix bz600027 (Fix cluster service creation/configuration UX issues)
+- Fix bz600040 (Add nodes to existing cluster does not work)
+- Fix bz600045 (Removing nodes from existing clusters fails)
+- Fix bz600055 ("cluster busy" dialog does not work)
+- Fix bz613868 (Remove fence_virsh from luci UI since this fence is not supported with RHEL HA/Cluster)
+- Fix bz614434 (adding an IP resource ends with an error 500)
+- Fix bz614439 (adding GFS2 resource type in RHEL6 cluster is "interesting")
+- Fix bz615096 (Traceback when unchecking "Prioritized" in Failover Domains)
+- Fix bz615468 (When creating a new failover domain, adding nodes has no effect)
+- Fix bz615872 (unicode error deleting a cluster)
+- Fix bz615889 (luci cannot start an imported cluster)
+- Fix bz615911 (luci shows many unsupported fence devices when adding a new fence device)
+- Fix bz615917 (adding per node fence instance results in error 500 if no fence devices are configured)
+- Fix bz615929 (luci generated cluster.conf with fence_scsi fails to validate)
+- Fix bz616094 (Deleting a fence device which is in use, causes a traceback on Nodes page)
+- Fix bz616228 (Clicking on cluster from manage clusters page results in traceback (500 error))
+- Fix bz616230 (Clicking on the join button doesn't work on nodes page)
+- Fix bz616244 (Clicking on the leave button doesn't work on nodes page.)
+
+* Wed Jul 14 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-8
+- Fix bz600021 (Fix node fence configuration UX issues)
+
+* Tue Jul 13 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-7
+- Build fix for bz600056
+
+* Tue Jul 13 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-6
+- Build fix for bz600056
+
+* Tue Jul 13 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-5
+- Fix bz604740 (Support nfsserver resource agent which is for NFSv4 and NFSv3)
+- Fix bz600056 (Replace logo image)
+
+* Fri Jul 09 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-4
+- Fix bz600059 (Hide optional fields for fence_scsi)
+- Fix bz600077 (cman "two_node" attribute should not be set when using qdisk)
+- Fix bz600083 (Add text to broadcast mode to note that it is for demos only - no production support)
+- Fix bz605780 (Qdisk shouldn't be part of the main page, it should be in the configuration tab)
+
+* Fri Jun 18 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-3
+- Fix bz598859 (Adding fence_xvm fence device through luci interface throws TypeError Traceback)
+- Fix bz599074 ("Use same password for all nodes" doesn't work.)
+- Fix bz599080 (Conga ignores "reboot nodes" check box)
+- Fix bz600047 (luci allows deletion of global resources that are used by services)
+- Fix bz600050 (luci requires wrongly requires users to fill interval / tko / minimum score / votes fields for qdisk configuration)
+- Fix bz600052 (luci allows deletion of the last qdisk heuristics row)
+- Fix bz600058 (ssh_identity field values are dropped)
+- Fix bz600060 (Formatting error on fence devices overview page)
+- Fix bz600061 (Default values not populated in advanced network configuration)
+- Fix bz600066 (Update resource agent labels)
+- Fix bz600069 (Configuration page always returns to General Properties Page)
+- Fix bz600071 (If luci cannot communicate with the nodes they don't appear in the list of nodes)
+- Fix bz600073 (Update resource agent list)
+- Fix bz600074 (Fix display error on the resource list page)
+- Fix bz600075 (update fence_virt / fence_xvm configuration)
+- Fix bz600076 (When creating a cluster no default radio button is selected for Download Packages/Use locally installed packages)
+- Fix bz600079 (Unable to edit existing resources)
+- Fix bz600080 (Homebase page only shows a '-' for Nodes Joined)
+- Fix bz602482 (Multicast settings are not relayed to cluster.conf and no default)
+- Fix bz603833 ("Nodes Joined" in main page is inaccurate when no nodes have joined)
+
+* Tue Jun 01 2010 Chris Feist <cfeist at redhat.com> - 0.22.2-2
+- Fix missing requires which will cause some installations to fail
+- Resolves: rhbz#598725
+
+* Fri May 26 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.2-1
+- Fix for bugs related to cluster service creation and editing (bz593836).
+
+* Wed May 26 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.1-3
+- Fix remaining unresolved issues for 593836
+  - Make sure the cluster version is updated when creating services
+  - Fix a bug that caused IP resources to fail in services
+
+* Wed May 26 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.1-2
+- Rebuild to fix a bug introduced during last build.
+
+* Wed May 26 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.1-1
+- Fix service creation, display, and edit.
+- Fix qdisk heuristic submission.
+
+* Wed May 19 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.0-16
+- Rebase to upstream
+
+* Mon May 17 2010 Chris Feist <cfeist at redhat.com> - 0.22.0-13
+- Added static UID/GID for luci user
+- Resolves: rhbz#585988
+
+* Wed May 12 2010 Chris Feist <cfeist at redhat.com> - 0.22.0-11
+- Add support for PAM authentication
+- Resync with main branch
+- Resolves: rhbz#518206
+
+* Wed May 12 2010 Fabio M. Di Nitto <fdinitto at redhat.com> - 0.21.0-8
+- Do not build on ppc and ppc64.
+  Resolves: rhbz#590987
+
+* Tue Apr 27 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.0-4
+- Update from devel tree.
+
+* Thu Apr 22 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.0-3
+- Update from development tree.
+
+* Thu Apr 08 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.0-2
+- Update from development tree.
+
+* Tue Mar 09 2010 Ryan McCabe <rmccabe at redhat.com> - 0.22.0-1
+- Rebase to luci version 0.22.0
+
+* Mon Mar  1 2010 Fabio M. Di Nitto <fdinitto at redhat.com> - 0.21.0-7
+- Resolves: rhbz#568005
+- Add ExcludeArch to drop s390 and s390x
+
+* Tue Jan 19 2010 Ryan McCabe <rmccabe at redhat.com> - 0.21.0-6
+- Remove dependency on python-tg-devtools
 
 * Wed Nov 04 2009 Ryan McCabe <rmccabe at redhat.com> - 0.21.0-4
 - And again.
diff --git a/sources b/sources
index 54895dd..dc93d41 100644
--- a/sources
+++ b/sources
@@ -1 +1,2 @@
-59e01361b7916081b15b2912bb56673f  luci-0.21.0.tar.bz2
+ec2d60536291953a941c6e7eb3a8c56d  luci-0.22.4.tar.bz2
+c1aec4cca9d3ea87b65543a1267ac4b6  logo.png
diff --git a/stolen_from_git.patch b/stolen_from_git.patch
new file mode 100644
index 0000000..77a6365
--- /dev/null
+++ b/stolen_from_git.patch
@@ -0,0 +1,854 @@
+diff --git a/luci.spec b/luci.spec
+index d82df03..7d31454 100644
+--- a/luci.spec
++++ b/luci.spec
+@@ -9,7 +9,7 @@ Summary: Web-based high availability administration application
+ Group: Applications/System
+ License: GPLv2
+ URL: http://sources.redhat.com/cluster/conga
+-Source0: http://people.redhat.com/rmccabe/luci/luci-0.22.3.tar.bz2
++Source0: http://people.redhat.com/rmccabe/luci/luci-0.22.4.tar.bz2
+ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+ BuildRequires: python-devel python-setuptools python-paste python-paste-script cyrus-sasl-devel
+ Requires: TurboGears2 openssl python-repoze-who-friendlyform python-tw-forms
+@@ -45,7 +45,7 @@ rm -rf %{buildroot}
+ %doc README.txt COPYING
+ %{python_sitelib}/%{name}-%{version}-py%{pyver}.egg-info/
+ %{python_sitelib}/%{name}/
+-%{python_sitelib_arch}/LuciPAM-1.0-py2.6.egg-info
++%{python_sitelib_arch}/LuciPAM-1.0-py%{pyver}.egg-info
+ %{python_sitelib_arch}/lucipam.so
+ 
+ %config(noreplace)      /etc/pam.d/luci
+diff --git a/luci/controllers/cluster.py b/luci/controllers/cluster.py
+index 62adfa2..86bc1e0 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
+@@ -89,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)
+@@ -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)
+@@ -727,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/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/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
+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/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/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>
+ 
+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
+diff --git a/lucipam/lucipam.c b/lucipam/lucipam.c
+index 334adcf..5aa61e6 100644
+--- a/lucipam/lucipam.c
++++ b/lucipam/lucipam.c
+@@ -23,7 +23,7 @@
+  * Author: Chris Feist <cfeist at redhat.com>
+  */
+ 
+-#include <python2.6/Python.h>
++#include <Python.h>
+ #include <sasl/sasl.h>
+ #include <string.h>
+ 


More information about the scm-commits mailing list