[luci] luci: Fix label on fence_hpblade form
by Ryan McCabe
commit f99f555d21a43b2243c2b71c0917b3f5b68c79cc
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Oct 15 12:52:14 2012 -0400
luci: Fix label on fence_hpblade form
Fix bad label on the fence_hpblade config form to read
"HP BladeSystem"
Resolves: rhbz#865533
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/templates/fence_devices.html | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/luci/templates/fence_devices.html b/luci/templates/fence_devices.html
index eb56b96..d0a2b4c 100644
--- a/luci/templates/fence_devices.html
+++ b/luci/templates/fence_devices.html
@@ -3326,7 +3326,7 @@
<table class="formtable">
<tr>
<td>Fence Type</td>
- <td>WTI Power Switch</td>
+ <td>HP BladeSystem</td>
</tr>
<tr>
<td>Name</td>
11 years, 7 months
[luci] luci: Add support for fence_hpblade
by Ryan McCabe
commit 6f6f815618e096f21eed5e00a2c2d98ddce4dd6d
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Fri Oct 12 00:00:27 2012 -0400
luci: Add support for fence_hpblade
Add an interface for configuring and displaying
fence_hpblade fence devices.
Resolves: rhbz#865533
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/lib/ClusterConf/FenceDeviceAttr.py | 3 +
luci/templates/fence_devices.html | 88 +++++++++++++++++++++++++++++++
luci/templates/fence_instances.html | 48 +++++++++++++++++
luci/validation/validate_fence.py | 27 +++++++++
4 files changed, 166 insertions(+), 0 deletions(-)
---
diff --git a/luci/lib/ClusterConf/FenceDeviceAttr.py b/luci/lib/ClusterConf/FenceDeviceAttr.py
index 135ed83..33a2564 100644
--- a/luci/lib/ClusterConf/FenceDeviceAttr.py
+++ b/luci/lib/ClusterConf/FenceDeviceAttr.py
@@ -20,6 +20,7 @@ FENCE_OPTS = {
'fence_gnbd': 'Global Network Block Device',
'fence_sanbox2': 'QLogic SANBox2',
'fence_bladecenter': 'IBM Blade Center',
+ 'fence_hpblade': 'HP BladeSystem',
'fence_mcdata': 'McDATA SAN Switch',
'fence_eaton_snmp': 'Eaton Network Power Controller (SNMP Interface)',
'fence_egenera': 'Egenera SAN Controller',
@@ -79,6 +80,8 @@ FENCE_SHARED = {
'fence_cisco_ucs': True,
'fence_eps': True,
'fence_ibmblade': True,
+ 'fence_hpblade': True,
+ 'fence_eaton_snmp': True,
'fence_ifmib': True,
'fence_ipdu': True,
'fence_intelmodular': True,
diff --git a/luci/templates/fence_devices.html b/luci/templates/fence_devices.html
index b76e6bf..eb56b96 100644
--- a/luci/templates/fence_devices.html
+++ b/luci/templates/fence_devices.html
@@ -3321,6 +3321,92 @@
<input type="hidden" name="fence_type" value="fence_eaton_snmp" />
</div>
+<div py:def="fence_hpblade(cur_fencedev, ni)" id="fence_hpblade" class="fencedevform row"
+ py:attrs="cur_fencedev and {'id': 'fd_%s' % cur_fencedev.getName()}">
+ <table class="formtable">
+ <tr>
+ <td>Fence Type</td>
+ <td>WTI Power Switch</td>
+ </tr>
+ <tr>
+ <td>Name</td>
+ <td>
+ <input name="name" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getName()} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>IP Address or Hostname</td>
+ <td>
+ <input name="ipaddr" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('ipaddr')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>IP Port (optional)</td>
+ <td>
+ <input name="ipport" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('ipport')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Login</td>
+ <td>
+ <input name="login" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('login')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Password</td>
+ <td>
+ <input name="passwd" type="password" class="text" autocomplete="off"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('passwd')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <span title="Full path to a script to generate fence password">Password Script (optional)</span>
+ </td>
+ <td>
+ <input type="text" class="text" name="passwd_script"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('passwd_script')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Force Command Prompt</td>
+ <td>
+ <input type="text" class="text" name="cmd_prompt"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('cmd_prompt')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Missing port returns OFF instead of failure</td>
+ <td>
+ <input type="checkbox" class="checkbox" name="missing_as_off"
+ py:attrs="cur_fencedev and cur_fencedev.getBinaryAttribute('missing_as_off') and {'checked': 'checked'}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Power Wait (seconds)</td>
+ <td>
+ <input type="text" class="text" name="power_wait"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('power_wait')} or {}"/>
+ </td>
+ </tr>
+ </table>
+
+ <py:if test="cur_fencedev">
+ <input type="hidden"
+ name="orig_name" value="${cur_fencedev.getName()}"/>
+ <input type="hidden"
+ name="existing_device" value="1" />
+ </py:if>
+
+ <input type="hidden" name="sharable" value="1" />
+ <input type="hidden" name="num_instances" value="${ni}"/>
+ <input type="hidden" name="fence_type" value="fence_hpblade" />
+</div>
+
<div py:def="fence_device_container" id="fence_device_container" class="hidden">
${fence_apc(None,0)}
${fence_apc_snmp(None,0)}
@@ -3362,6 +3448,7 @@ ${fence_rackswitch(None,0)}
${fence_xcat(None,0)}
${fence_zvm(None,0)}
${fence_ibmblade(None,0)}
+${fence_hpblade(None,0)}
${fence_eaton_snmp(None,0)}
${fence_unknown(None,0)}
</div>
@@ -3417,6 +3504,7 @@ ${fence_unknown(None,0)}
<option py:if="cluster_version == 2" name="fence_xvm" value="fence_xvm">Fence xvm</option>
<option name="fence_rsb" value="fence_rsb">Fujitsu Siemens RemoteView Service Board</option>
+ <option name="fence_hpblade" value="fence_hpblade">HP BladeSystem</option>
<option name="fence_ilo" value="fence_ilo">HP iLO Device</option>
<option name="fence_ilo_mp" value="fence_ilo_mp">HP iLO MP</option> <!-- needs work -->
<option name="fence_bladecenter" value="fence_bladecenter">IBM BladeCenter</option>
diff --git a/luci/templates/fence_instances.html b/luci/templates/fence_instances.html
index f2e3dde..66721c6 100644
--- a/luci/templates/fence_instances.html
+++ b/luci/templates/fence_instances.html
@@ -1063,6 +1063,53 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
+<div py:def="fence_hpblade_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_hpblade_instance"
+ py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
+ <table class="detailstable">
+ <tr>
+ <td>Port</td>
+ <td>
+ <input name="port" type="text" class="text"
+ py:attrs="cur_fence_inst and {'value': cur_fence_inst.getAttribute('port')}"/>
+ </td>
+ </tr>
+ <tr><td>
+ <fieldset>
+ <legend>SSH</legend>
+ <table class="detailstable">
+ <tr>
+ <td>
+ <span title="Enable SSH operation">Use SSH</span>
+ </td>
+ <td>
+ <input type="checkbox" class="checkbox" name="secure"
+ py:attrs="cur_fence_inst and cur_fence_inst.getAttribute('secure') and {'checked': 'checked'}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Path to SSH Identity File</td>
+ <td>
+ <input type="text" class="text" name="identity_file"
+ py:attrs="cur_fence_inst and {'value': cur_fence_inst.getAttribute('identity_file')}"/>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </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_hpblade" />
+ <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, **kw)" id="fence_unknown_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
@@ -1087,6 +1134,7 @@ ${fence_apc_instance(None, None, None)}
${fence_apc_snmp_instance(None, None, None)}
${fence_eaton_snmp_instance(None, None, None)}
${fence_egenera_instance(None, None, None)}
+${fence_hpblade_instance(None, None, None)}
${fence_lpar_instance(None, None, None)}
${fence_vmware_instance(None, None, None)}
${fence_vmware_soap_instance(None, None, None)}
diff --git a/luci/validation/validate_fence.py b/luci/validation/validate_fence.py
index bb2e6af..af6c965 100644
--- a/luci/validation/validate_fence.py
+++ b/luci/validation/validate_fence.py
@@ -510,6 +510,21 @@ def val_ibmblade_fd(fencedev, fence_name, **kw):
errors = config_fence_attr(params, fencedev, fence_name, **kw)
return errors
+def val_hpblade_fd(fencedev, fence_name, **kw):
+ params = (
+ ('ipaddr', True),
+ ('ipport', False),
+ ('login', True),
+ ('missing_as_off', False),
+ ('cmd_prompt', False),
+ ('passwd', False),
+ ('passwd_script', False),
+ ('power_wait', False),
+ )
+
+ errors = config_fence_attr(params, fencedev, fence_name, **kw)
+ return errors
+
def val_ifmib_fd(fencedev, fence_name, **kw):
params = (
('ipaddr', True),
@@ -712,6 +727,7 @@ FD_VALIDATE = {
'fence_egenera': val_egenera_fd,
'fence_eps': val_eps_fd,
'fence_gnbd': val_gnbd_fd,
+ 'fence_hpblade': val_hpblade_fd,
'fence_ibmblade': val_ibmblade_fd,
'fence_ifmib': val_ifmib_fd,
'fence_ilo_mp': val_ilo_mp_fd,
@@ -1005,6 +1021,16 @@ def val_ibmblade_fi(fenceinst, parent_name, **kw):
errors = config_fence_attr(params, fenceinst, parent_name, **kw)
return errors
+def val_hpblade_fi(fenceinst, parent_name, **kw):
+ params = (
+ ('port', True),
+ ('secure', False),
+ ('identity_file', False),
+ )
+
+ errors = config_fence_attr(params, fenceinst, parent_name, **kw)
+ return errors
+
def val_ifmib_fi(fenceinst, parent_name, **kw):
params = (
('port', True),
@@ -1072,6 +1098,7 @@ FI_VALIDATE = {
'fence_egenera': val_egenera_fi,
'fence_eps': val_eps_fi,
'fence_gnbd': val_gnbd_fi,
+ 'fence_hpblade': val_hpblade_fi,
'fence_ibmblade': val_ibmblade_fi,
'fence_ifmib': val_ifmib_fi,
'fence_ilo_mp': val_noop_fi,
11 years, 7 months
[luci] luci: Add support for fence_eaton_snmp
by Ryan McCabe
commit 610457357deaa20fda93eed51d648d4346950fc0
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Thu Oct 11 23:41:16 2012 -0400
luci: Add support for fence_eaton_snmp
Add an interface for configuring and displaying
fence_eaton_snmp fence devices.
Resolves: rhbz#865300
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/lib/ClusterConf/FenceDeviceAttr.py | 1 +
luci/templates/fence_devices.html | 153 +++++++++++++++++++++++++++++++
luci/templates/fence_instances.html | 34 +++++++
luci/validation/validate_fence.py | 29 ++++++
4 files changed, 217 insertions(+), 0 deletions(-)
---
diff --git a/luci/lib/ClusterConf/FenceDeviceAttr.py b/luci/lib/ClusterConf/FenceDeviceAttr.py
index 9775b00..135ed83 100644
--- a/luci/lib/ClusterConf/FenceDeviceAttr.py
+++ b/luci/lib/ClusterConf/FenceDeviceAttr.py
@@ -21,6 +21,7 @@ FENCE_OPTS = {
'fence_sanbox2': 'QLogic SANBox2',
'fence_bladecenter': 'IBM Blade Center',
'fence_mcdata': 'McDATA SAN Switch',
+ 'fence_eaton_snmp': 'Eaton Network Power Controller (SNMP Interface)',
'fence_egenera': 'Egenera SAN Controller',
'fence_bullpap': 'Bull PAP',
'fence_xvm': 'xvm Virtual Machine Fencing',
diff --git a/luci/templates/fence_devices.html b/luci/templates/fence_devices.html
index 97a4bb2..b76e6bf 100644
--- a/luci/templates/fence_devices.html
+++ b/luci/templates/fence_devices.html
@@ -3170,6 +3170,157 @@
<input type="hidden" name="fence_type" value="fence_ibmblade" />
</div>
+<div py:def="fence_eaton_snmp(cur_fencedev, ni)" id="fence_eaton_snmp" class="fencedevform row"
+ py:attrs="cur_fencedev and {'id': 'fd_%s' % cur_fencedev.getName()}">
+ <table class="formtable">
+ <tr>
+ <td>Fence Type</td>
+ <td>Eaton Network Power Switch (SNMP interface)</td>
+ </tr>
+ <tr>
+ <td>Name</td>
+ <td>
+ <input name="name" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getName()} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>IP Address or Hostname</td>
+ <td>
+ <input name="ipaddr" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('ipaddr')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>UDP/TCP Port (optional, defaults to 161)</td>
+ <td>
+ <input name="udpport" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('udpport')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Login</td>
+ <td>
+ <input name="login" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('login')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Password</td>
+ <td>
+ <input name="passwd" type="password" class="text" autocomplete="off"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('passwd')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <span title="Full path to a script to generate fence password">Password Script (optional)</span>
+ </td>
+ <td>
+ <input type="text" class="text" name="passwd_script"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('passwd_script')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>SNMP Version</td>
+ <td>
+ <select name="snmp_version">
+ <option value=""
+ py:attrs="(not cur_fencedev or not cur_fencedev.getAttribute('snmp_version')) and {'selected':'selected'} or {}">Default</option>
+ <option value="1"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_version') == '1' and {'selected':'selected'} or {}">1</option>
+ <option value="2c"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_version') == '2c' and {'selected':'selected'} or {}">2c</option>
+ <option value="3"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_version') == '3' and {'selected':'selected'} or {}">3</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>SNMP Community</td>
+ <td>
+ <input name="community" type="text" class="text"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('community')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>SNMP Security Level</td>
+ <td>
+ <select name="snmp_sec_level">
+ <option value=""
+ py:attrs="(not cur_fencedev or not cur_fencedev.getAttribute('snmp_sec_level')) and {'selected':'selected'} or {}">Default</option>
+ <option value="noAuthNoPriv"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_sec_level') == 'noAuthNoPriv' and {'selected':'selected'} or {}">noAuthNoPriv</option>
+ <option value="authNoPriv"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_sec_level') == 'authNoPriv' and {'selected':'selected'} or {}">authNoPriv</option>
+ <option value="authPriv"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_sec_level') == 'authPriv' and {'selected':'selected'} or {}">authPriv</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>SNMP Authentication Protocol</td>
+ <td>
+ <select name="snmp_auth_prot">
+ <option value=""
+ py:attrs="(not cur_fencedev or not cur_fencedev.getAttribute('snmp_auth_prot')) and {'selected':'selected'} or {}">Default</option>
+ <option value="MD5"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_auth_prot') == 'MD5' and {'selected':'selected'} or {}">MD5</option>
+ <option value="SHA"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_auth_prot') == 'SHA' and {'selected':'selected'} or {}">SHA</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>SNMP Privacy Protocol</td>
+ <td>
+ <select name="snmp_priv_prot">
+ <option value=""
+ py:attrs="(not cur_fencedev or not cur_fencedev.getAttribute('snmp_priv_prot')) and {'selected':'selected'} or {}">Default</option>
+ <option value="DES"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_priv_prot') == 'DES' and {'selected':'selected'} or {}">DES</option>
+ <option value="AES"
+ py:attrs="cur_fencedev and cur_fencedev.getAttribute('snmp_priv_prot') == 'AES' and {'selected':'selected'} or {}">AES</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td>SNMP Privacy Protocol Password</td>
+ <td>
+ <input name="snmp_priv_passwd" type="password" class="text" autocomplete="off"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('snmp_priv_passwd')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ SNMP Privacy Protocol Script
+ </td>
+ <td>
+ <input type="text" class="text" name="snmp_priv_passwd_script"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('snmp_priv_passwd_script')} or {}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Power Wait (seconds)</td>
+ <td>
+ <input type="text" class="text" name="power_wait"
+ py:attrs="cur_fencedev and {'value': cur_fencedev.getAttribute('power_wait')} or {}"/>
+ </td>
+ </tr>
+ </table>
+
+ <py:if test="cur_fencedev">
+ <input type="hidden"
+ name="orig_name" value="${cur_fencedev.getName()}"/>
+ <input type="hidden"
+ name="existing_device" value="1" />
+ </py:if>
+
+ <input type="hidden" name="sharable" value="1" />
+ <input type="hidden" name="num_instances" value="${ni}"/>
+ <input type="hidden" name="fence_type" value="fence_eaton_snmp" />
+</div>
+
<div py:def="fence_device_container" id="fence_device_container" class="hidden">
${fence_apc(None,0)}
${fence_apc_snmp(None,0)}
@@ -3211,6 +3362,7 @@ ${fence_rackswitch(None,0)}
${fence_xcat(None,0)}
${fence_zvm(None,0)}
${fence_ibmblade(None,0)}
+${fence_eaton_snmp(None,0)}
${fence_unknown(None,0)}
</div>
@@ -3252,6 +3404,7 @@ ${fence_unknown(None,0)}
<option py:if="cluster_version == 3" name="fence_drac" value="fence_drac">Dell DRAC (Deprecated)</option>
<option name="fence_drac5" value="fence_drac5">Dell DRAC 5</option> <!-- needs work -->
+ <option py:if="cluster_version == 3" name="fence_eaton_snmp" value="fence_eaton_snmp">Eaton Network Power Switch (SNMP interface)</option>
<option name="fence_egenera" value="fence_egenera">Egenera SAN Controller</option>
<option name="fence_eps" value="fence_eps">ePowerSwitch</option>
diff --git a/luci/templates/fence_instances.html b/luci/templates/fence_instances.html
index 9bfada3..f2e3dde 100644
--- a/luci/templates/fence_instances.html
+++ b/luci/templates/fence_instances.html
@@ -1039,6 +1039,30 @@
py:attrs="cur_fence_dev_id and {'value': cur_fence_dev_id} or {}" />
</div>
+<div py:def="fence_eaton_snmp_instance(cur_fence_inst, cur_fence_dev_id, fi_id, **kw)" id="fence_eaton_snmp_instance"
+ py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
+ <table class="detailstable">
+ <tr>
+ <td>Port (Outlet) Number</td>
+ <td>
+ <input name="port" type="text" class="text"
+ py:attrs="cur_fence_inst and {'value': cur_fence_inst.getAttribute('port')}"/>
+ </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_eaton_snmp" />
+ <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, **kw)" id="fence_unknown_instance"
py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
@@ -1048,10 +1072,20 @@
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, **kw)" id="fence_drac_instance"
+ py:attrs="fi_id is not None and {'id': fi_id, 'class':'fenceinst'}">
+
+ <div class="emptyfenceinst">No additional parameters</div>
+ <input type="hidden" name="fence_type" value="fence_drac" />
+ <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_instance_container(nodename)"
id="fence_instance_container" class="hidden">
${fence_apc_instance(None, None, None)}
${fence_apc_snmp_instance(None, None, None)}
+${fence_eaton_snmp_instance(None, None, None)}
${fence_egenera_instance(None, None, None)}
${fence_lpar_instance(None, None, None)}
${fence_vmware_instance(None, None, None)}
diff --git a/luci/validation/validate_fence.py b/luci/validation/validate_fence.py
index 2ea032e..bb2e6af 100644
--- a/luci/validation/validate_fence.py
+++ b/luci/validation/validate_fence.py
@@ -662,6 +662,26 @@ def val_ipdu_fd(fencedev, fence_name, **kw):
errors = config_fence_attr(params, fencedev, fence_name, **kw)
return errors
+def val_eaton_snmp_fd(fencedev, fence_name, **kw):
+ params = (
+ ('ipaddr', True),
+ ('udpport', False),
+ ('login', True),
+ ('passwd', False),
+ ('passwd_script', False),
+ ('community', False),
+ ('snmp_version', False),
+ ('snmp_sec_level', False),
+ ('snmp_auth_prot', False),
+ ('snmp_priv_prot', False),
+ ('snmp_priv_passwd', False),
+ ('snmp_priv_passwd_script', False),
+ ('power_wait', False),
+ )
+
+ errors = config_fence_attr(params, fencedev, fence_name, **kw)
+ return errors
+
def val_rhevm_fd(fencedev, fence_name, **kw):
params = (
('ipaddr', True),
@@ -688,6 +708,7 @@ FD_VALIDATE = {
'fence_cpint': val_cpint_fd,
'fence_drac5': val_drac5_fd,
'fence_drac': val_drac_fd,
+ 'fence_eaton_snmp': val_eaton_snmp_fd,
'fence_egenera': val_egenera_fd,
'fence_eps': val_eps_fd,
'fence_gnbd': val_gnbd_fd,
@@ -1025,6 +1046,13 @@ def val_rhevm_fi(fenceinst, parent_name, **kw):
errors = config_fence_attr(params, fenceinst, parent_name, **kw)
return errors
+def val_eaton_snmp_fi(fenceinst, parent_name, **kw):
+ params = (
+ ('port', True),
+ )
+
+ errors = config_fence_attr(params, fenceinst, parent_name, **kw)
+ return errors
def val_noop_fi(fenceinst, parent_name, **kw):
return []
@@ -1040,6 +1068,7 @@ FI_VALIDATE = {
'fence_cpint': val_noop_fi,
'fence_drac5': val_noop_fi,
'fence_drac': val_noop_fi,
+ 'fence_eaton_snmp': val_eaton_snmp_fi,
'fence_egenera': val_egenera_fi,
'fence_eps': val_eps_fi,
'fence_gnbd': val_gnbd_fi,
11 years, 7 months
[luci] luci: Add back missing unfence patch
by Ryan McCabe
commit 9b51bbb9be3d525e71d0974d832ff6c5315d1546
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Wed Oct 10 21:53:13 2012 -0400
luci: Add back missing unfence patch
Part of the fix for the unfence display issue went AWOL.
This adds it back.
Resolves: rhbz#815666
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/templates/node.html | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
---
diff --git a/luci/templates/node.html b/luci/templates/node.html
index f749706..874c8f9 100644
--- a/luci/templates/node.html
+++ b/luci/templates/node.html
@@ -18,9 +18,7 @@
<body py:with="cluster_data = tmpl_context.cluster.get_model();
cluster_status = tmpl_context.cluster.get_status();
- nodename = (cluster_data and cluster_data.cluster_version <= 2 and name) and name or None;">
- <!--! "nodename" parameter is spread to fence_scsi only under
- given conditions -->
+ nodename = name;">
<script type="text/javascript" src="/js/add_nodes.js"></script>
<script type="text/javascript" src="/js/node.js"></script>
11 years, 7 months
[luci] luci: Add the ability to remove users
by Ryan McCabe
commit c43a44d2d51e4c356ae8a52aaea31aef54e6a4dd
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Oct 8 23:33:55 2012 -0400
luci: Add the ability to remove users
Add an interface to remove user DB objects.
Resolves: rhbz#809892
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/controllers/root.py | 11 +++++++++
luci/lib/db_helpers.py | 10 +++++++-
luci/model/auth.py | 5 ++++
luci/templates/admin.html | 37 ++++++++++++++++++++++++++++++
luci/validation/validate_cluster_prop.py | 33 ++++++++++++++++++++++++++
5 files changed, 95 insertions(+), 1 deletions(-)
---
diff --git a/luci/controllers/root.py b/luci/controllers/root.py
index 21b5f6f..a2c6cd3 100644
--- a/luci/controllers/root.py
+++ b/luci/controllers/root.py
@@ -115,6 +115,17 @@ class RootController(BaseController):
flash(','.join(ret[1]['errors']), status="error")
else:
flash(_("Settings Applied"))
+ elif command == 'deluser':
+ ret = vcp.validate_user_delete(name, **args)
+ if ret[0] is False:
+ if ret[1].has_key('errors'):
+ flash(','.join(ret[1]['errors']), status="error")
+ else:
+ msgs = ret[1].get('flash')
+ if msgs and len(msgs) > 0:
+ flash(', '.join(msgs))
+ else:
+ flash(_('Unknown command: %s') % command, status="error")
return dict(page='admin')
@expose('luci.templates.homebase')
diff --git a/luci/lib/db_helpers.py b/luci/lib/db_helpers.py
index 6f79aa8..0b7daa3 100644
--- a/luci/lib/db_helpers.py
+++ b/luci/lib/db_helpers.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2009-2011 Red Hat, Inc.
+# Copyright (C) 2009-2012 Red Hat, Inc.
#
# This program is free software; you can redistribute
# it and/or modify it under the terms of version 2 of the
@@ -560,6 +560,14 @@ def update_db_objects():
DBSession.add(grole)
transaction.commit()
+def get_user_list():
+ ret = []
+ try:
+ ret = DBSession.query(User).all()
+ except:
+ log.exception("Getting user list")
+ return ret
+
def get_user_names():
ret = []
try:
diff --git a/luci/model/auth.py b/luci/model/auth.py
index cff8f7b..8fe3335 100644
--- a/luci/model/auth.py
+++ b/luci/model/auth.py
@@ -151,6 +151,11 @@ class User(DeclarativeBase):
"""Return the user object whose user name is ``username``."""
return DBSession.query(cls).filter(cls.user_name==username).first()
+ @classmethod
+ def by_user_id(cls, userid):
+ """Return the user object whose user id is ``userid``."""
+ return DBSession.query(cls).filter(cls.user_id==userid).first()
+
def _set_password(self, password):
"""Hash ``password`` on the fly and store its hashed version."""
hashed_password = password
diff --git a/luci/templates/admin.html b/luci/templates/admin.html
index 5c1f44e..5fd1b31 100644
--- a/luci/templates/admin.html
+++ b/luci/templates/admin.html
@@ -49,14 +49,51 @@
<div id="tabs-1">
<h2>Users and Permissions</h2>
+ <h4>Existing Users</h4>
+ <form name="manage_edit" method="post" action="${tg.url('admin_cmd' + '?command=deluser')}">
+ <table class="maintable" id="overview"
+ py:with="user_list = db_helpers.get_user_list()">
+ <thead>
+ <tr>
+ <th>
+ <input type="checkbox" name="check_all_users"
+ onchange="if ($(this).is(':checked')) {$('input:checkbox.userdel').attr('checked', 'checked');} else {$('input:checkbox.userdel').removeAttr('checked');}"/>
+ </th>
+ <th>User name</th>
+ <th>User ID</th>
+ <th>Created</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr py:for="(i, cur_user) in enumerate(user_list)"
+ py:attrs="not i%2 and {'class': 'even'} or {}">
+ <td>
+ <input class="checkbox userdel" type="checkbox"
+ name="uid${cur_user.user_id}"
+ py:attrs="cur_user.user_id == 1 and {'disabled':'disabled'} or {}"/>
+ </td>
+ <td>${cur_user.user_name}</td>
+ <td>${cur_user.user_id}</td>
+ <td>${cur_user.created}</td>
+ </tr>
+ </tbody>
+ </table>
+ <div>
+ <br/>
+ <input type="submit" class="small button silver" value="Delete Selected"/>
+ </div>
+ </form>
+
<div id="cluster_perms">
<form name="user_select" method="get" action="${tg.url('/admin')}">
+ <h4>Add New User</h4>
<p>
<p>
<input type="button" class="small button silver"
value="Add a User"
onclick="$('#add_user_dialog').dialog('open')"/>
</p>
+ <h4>User Permissions</h4>
<select name="name" onchange="this.form.submit()"
py:with="usernames = db_helpers.get_user_names() or []">
<option value=""
diff --git a/luci/validation/validate_cluster_prop.py b/luci/validation/validate_cluster_prop.py
index a754d40..62d0a9d 100644
--- a/luci/validation/validate_cluster_prop.py
+++ b/luci/validation/validate_cluster_prop.py
@@ -22,6 +22,7 @@ from luci.lib.ricci_communicator import RicciCommunicator
from luci.lib.ricci_helpers import send_batch_parallel
from luci.model import DBSession
+import transaction
from luci.model.auth import User, Group
from validate_fence import validateFenceDevice, validateNewFenceDevice, validate_fenceinstance
@@ -1307,6 +1308,38 @@ def validate_add_user(name, **kw):
return (True, {})
return (False, {'errors': [err]})
+def validate_user_delete(name, **kw):
+ errors = []
+ kill_list = []
+
+ for k in kw:
+ if k.startswith('uid'):
+ try:
+ cur_user = User.by_user_id(int(k[3:]))
+ except:
+ log.exception("User lookup %s" % k)
+ continue
+
+ if cur_user.user_id == 1:
+ errors.append(_('The root user may not be removed'))
+ else:
+ kill_list.append(cur_user)
+
+ del_count = len(kill_list)
+ try:
+ for k in kill_list:
+ DBSession.delete(k)
+ transaction.commit()
+ except:
+ errors.append(_('Unable to remove users'))
+ log.exception('Removing users')
+ DBSession.rollback()
+
+ if errors:
+ return (False, {'errors': errors})
+
+ return (True, {'flash': [_('%d users removed') % del_count]})
+
def validate_user_perms(name, **kw):
errors = []
11 years, 7 months
[luci] luci: Add global resources to be referenced multiple times
by Ryan McCabe
commit f822ec0b85838fed3662eab192be31bd5ed9c34d
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Oct 8 09:56:17 2012 -0400
luci: Add global resources to be referenced multiple times
Allow global resources to be referenced more than once inside
a service group.
Resolves: rhbz#860042
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/validation/validate_resource.py | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
---
diff --git a/luci/validation/validate_resource.py b/luci/validation/validate_resource.py
index da4ae91..7969e0b 100644
--- a/luci/validation/validate_resource.py
+++ b/luci/validation/validate_resource.py
@@ -766,7 +766,8 @@ def validate_clusvc_form(model, **kw):
else:
dummy_form['resourcename'] = dummy_form['address_nominal']
dummy_form['address'] = dummy_form['resourcename']
- if dummy_form.has_key('resourcename'):
+ if (dummy_form.has_key('resourcename')
+ and not dummy_form.has_key('global')):
if dummy_form['resourcename'] in existing_res_names:
return (False, { 'errors': [ _('A resource named "%s" already exists') % dummy_form['resourcename'] ]})
else:
11 years, 7 months
[luci] luci: Fix double click on add existing dialog
by Ryan McCabe
commit 72fa237fc759c83c927d87bad5ee8d51dab3c0db
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Oct 8 09:55:18 2012 -0400
luci: Fix double click on add existing dialog
Fix a bug that caused nodes to be listed twice if you accidentally
double clicked the "Connect" button on the add existing cluster
dialog.
Resolves: rhbz#856253
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/public/js/add_existing.js | 4 ++++
luci/templates/add_existing.html | 2 +-
2 files changed, 5 insertions(+), 1 deletions(-)
---
diff --git a/luci/public/js/add_existing.js b/luci/public/js/add_existing.js
index 59b99b9..25d742c 100644
--- a/luci/public/js/add_existing.js
+++ b/luci/public/js/add_existing.js
@@ -5,13 +5,16 @@ function add_existing_callback(data) {
if (data) {
if ('errors' in data) {
alert('Error adding this cluster: ' + data['errors'].join(' '));
+ $("#connect_button").removeAttr('disabled', 'disabled');
return;
} else if (!'nodes' in data) {
alert('Unable to retrieve the list of cluster nodes');
+ $("#connect_button").removeAttr('disabled', 'disabled');
return;
}
var tbody_elem = $("#sys_tbody");
if (!tbody_elem) {
+ $("#connect_button").removeAttr('disabled', 'disabled');
return;
}
var num_nodes;
@@ -43,6 +46,7 @@ function add_existing_async(form) {
if (!form.port) {
errors.append('No port was given');
}
+ $("#connect_button").attr('disabled', 'disabled');
$.post("/async/get_cluster_nodes",
{
'host': form.hostname.value,
diff --git a/luci/templates/add_existing.html b/luci/templates/add_existing.html
index cf3cb30..dad5519 100644
--- a/luci/templates/add_existing.html
+++ b/luci/templates/add_existing.html
@@ -19,7 +19,7 @@
</tr>
</table>
</div>
- <input type="button" class="button formsubmit blue" value="Connect" onclick="add_existing_async(this.form)" />
+ <input id="connect_button" type="button" class="button formsubmit blue" value="Connect" onclick="add_existing_async(this.form)" />
<input type="button" class="button formsubmit silver" value="Cancel"
onclick="$('#add_existing_dialog').dialog('close');reset_form(this.form)" />
</form>
11 years, 7 months
[luci] luci: Add support for nfsrestart
by Ryan McCabe
commit e86b26b8d90b594b0d31f3d57d592f132b311e4f
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Oct 8 09:54:25 2012 -0400
luci: Add support for nfsrestart
Add support for configuring and displaying the nfsrestart attribute
for filesystem and clusterfs resources.
Resolves: rhbz#822502
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/public/js/resource.js | 14 +++++++++
luci/templates/resource_list.html | 50 ++++++++++++++++++++++-----------
luci/validation/validate_resource.py | 8 +++++
3 files changed, 55 insertions(+), 17 deletions(-)
---
diff --git a/luci/public/js/resource.js b/luci/public/js/resource.js
index 8e6f432..a839875 100644
--- a/luci/public/js/resource.js
+++ b/luci/public/js/resource.js
@@ -18,3 +18,17 @@ function swap_resource_form(resource_form_id) {
$('#resource_form_area').empty();
form_jelem.clone().appendTo('#resource_form_area');
}
+
+function forceunmount_update(form) {
+ var nfsrestart_cb = form.nfsrestart;
+ if (!nfsrestart_cb) {
+ return;
+ }
+
+ if (form.force_unmount.checked) {
+ nfsrestart_cb.disabled = false;
+ } else {
+ nfsrestart_cb.checked = false;
+ nfsrestart_cb.disabled = true;
+ }
+}
diff --git a/luci/templates/resource_list.html b/luci/templates/resource_list.html
index ebcd2a7..d914922 100644
--- a/luci/templates/resource_list.html
+++ b/luci/templates/resource_list.html
@@ -107,7 +107,7 @@
<td>Disable Updates to Static Routes</td>
<td>
<input type="checkbox" class="checkbox" name="disable_rdisc"
- py:attrs="res and {'checked': res.getAttribute('disable_rdisc') and 'checked' or None, 'disabled':global_resource and 'disabled' or None} or {}" />
+ py:attrs="res and {'checked': res.getBinaryAttribute('disable_rdisc') and 'checked' or None, 'disabled':global_resource and 'disabled' or None} or {}" />
</td>
</tr>
<tr>
@@ -201,28 +201,36 @@
<td>Force Unmount</td>
<td>
<input type="checkbox" class="checkbox" name="force_unmount"
- py:attrs="{'checked':(res and res.getAttribute('force_unmount')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ onchange="forceunmount_update(this.form)"
+ py:attrs="{'checked':(res and res.getBinaryAttribute('force_unmount')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
<td>Force fsck</td>
<td>
<input type="checkbox" class="checkbox" name="force_fsck"
- py:attrs="{'checked':(res and res.getAttribute('force_fsck')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('force_fsck')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ </td>
+ </tr>
+ <tr>
+ <td>Enable NFS daemon and lockd workaround</td>
+ <td>
+ <input type="checkbox" class="checkbox" name="nfsrestart"
+ py:attrs="{'checked':(res and res.getBinaryAttribute('nfsrestart')) and 'checked' or None, 'disabled':(global_resource or not res or not res.getBinaryAttribute('force_unmount')) and 'disabled' or None}" />
</td>
</tr>
<tr>
<td>Use Quick Status Checks</td>
<td>
<input type="checkbox" class="checkbox" name="quick_status"
- py:attrs="{'checked':(res and res.getAttribute('quick_status')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('quick_status')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
<td>Reboot Host Node if Unmount Fails</td>
<td>
<input type="checkbox" class="checkbox" name="self_fence"
- py:attrs="{'checked':(res and res.getAttribute('self_fence')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('self_fence')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
${res_footer(res)}
@@ -309,14 +317,22 @@
<td>Force Unmount</td>
<td>
<input type="checkbox" class="checkbox" name="force_unmount"
- py:attrs="{'checked':(res and res.getAttribute('force_unmount')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ onchange="forceunmount_update(this.form)"
+ py:attrs="{'checked':(res and res.getBinaryAttribute('force_unmount')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ </td>
+ </tr>
+ <tr>
+ <td>Enable NFS daemon and lockd workaround</td>
+ <td>
+ <input type="checkbox" class="checkbox" name="nfsrestart"
+ py:attrs="{'checked':(res and res.getBinaryAttribute('nfsrestart')) and 'checked' or None, 'disabled':(global_resource or not res or not res.getBinaryAttribute('force_unmount')) and 'disabled' or None}" />
</td>
</tr>
<tr>
<td>Reboot Host Node if Unmount Fails</td>
<td>
<input type="checkbox" class="checkbox" name="self_fence"
- py:attrs="{'checked':(res and res.getAttribute('self_fence')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('self_fence')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
${res_footer(res)}
@@ -382,14 +398,14 @@
<td>Do Not Unmount the Filesystem During a Stop or Relocation Operation</td>
<td>
<input type="checkbox" class="checkbox" name="no_unmount"
- py:attrs="{'checked':(res and res.getAttribute('no_unmount')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('no_unmount')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
<td>Force Unmount</td>
<td>
<input type="checkbox" class="checkbox" name="force_unmount"
- py:attrs="{'checked':(res and res.getAttribute('force_unmount')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('force_unmount')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
@@ -510,7 +526,7 @@
<td>Allow Recovery of This NFS Client</td>
<td>
<input type="checkbox" class="checkbox" name="allow_recover"
- py:attrs="{'checked':(res and res.getAttribute('allow_recover')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('allow_recover')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
@@ -785,7 +801,7 @@
<td>Fence the Node if It is Unable to Clean Up LVM Tags</td>
<td>
<input type="checkbox" class="checkbox" name="self_fence"
- py:attrs="{'checked':(res and res.getAttribute('self_fence')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('self_fence')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
${res_footer(res)}
@@ -1066,7 +1082,7 @@
</td>
<td>
<input type="checkbox" class="checkbox" name="AUTOMATIC_RECOVER"
- py:attrs="{'checked':(res and res.getAttribute('AUTOMATIC_RECOVER')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('AUTOMATIC_RECOVER')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
@@ -1164,21 +1180,21 @@
<td>ABAP Stack Is Not Installed, Only Java Stack Is Installed</td>
<td>
<input type="checkbox" class="checkbox" name="DBJ2EE_ONLY"
- py:attrs="{'checked':(res and res.getAttribute('DBJ2EE_ONLY')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('DBJ2EE_ONLY')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
<td>Application Level Monitoring</td>
<td>
<input type="checkbox" class="checkbox" name="STRICT_MONITORING"
- py:attrs="{'checked':(res and res.getAttribute('STRICT_MONITORING')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('STRICT_MONITORING')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
<td>Automatic Startup Recovery</td>
<td>
<input type="checkbox" class="checkbox" name="AUTOMATIC_RECOVER"
- py:attrs="{'checked':(res and res.getAttribute('AUTOMATIC_RECOVER')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
+ py:attrs="{'checked':(res and res.getBinaryAttribute('AUTOMATIC_RECOVER')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}" />
</td>
</tr>
<tr>
@@ -1553,7 +1569,7 @@
<td>Use Simplified Database Backend</td>
<td>
<input type="checkbox" class="checkbox" name="named_sdb"
- py:attrs="{'checked':(res and res.getAttribute('named_sdb')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}"/>
+ py:attrs="{'checked':(res and res.getBinaryAttribute('named_sdb')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}"/>
</td>
</tr>
<tr>
@@ -1721,7 +1737,7 @@
<td>Tunnel data over ssh during migration</td>
<td>
<input type="checkbox" class="checkbox" name="tunnelled"
- py:attrs="{'checked':(res and res.getAttribute('tunnelled')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}"/>
+ py:attrs="{'checked':(res and res.getBinaryAttribute('tunnelled')) and 'checked' or None, 'disabled':global_resource and 'disabled' or None}"/>
</td>
</tr>
${res_footer(res)}
diff --git a/luci/validation/validate_resource.py b/luci/validation/validate_resource.py
index f499d47..da4ae91 100644
--- a/luci/validation/validate_resource.py
+++ b/luci/validation/validate_resource.py
@@ -131,6 +131,7 @@ def addFs(res, rname, model, **kw):
('self_fence', '', False, None),
('fsid', '', False, None),
('force_fsck', '', False, None),
+ ('nfsrestart', '', False, None),
('options', '', False, None)
)
errors = config_resource(params, res, rname, **kw)
@@ -141,6 +142,9 @@ def addFs(res, rname, model, **kw):
else:
if not fsid_is_unique(model, int(fsid)):
errors.append(_('fsid for resource %s is not unique') % rname)
+ if (res.getBinaryAttribute('nfsrestart')
+ and not res.getBinaryAttribute('force_unmount')):
+ errors.append(_('nfsrestart requires force_unmount to be enabled'))
return errors
def addClusterfs(res, rname, model, **kw):
@@ -149,6 +153,7 @@ def addClusterfs(res, rname, model, **kw):
('device', '', True, None),
('fstype', '', False, None),
('force_unmount', '', False, None),
+ ('nfsrestart', '', False, None),
('self_fence', '', False, None),
('fsid', '', False, None),
('options', '', False, None)
@@ -161,6 +166,9 @@ def addClusterfs(res, rname, model, **kw):
else:
if not fsid_is_unique(model, int(fsid)):
errors.append(_('fsid for resource %s is not unique') % rname)
+ if (res.getBinaryAttribute('nfsrestart')
+ and not res.getBinaryAttribute('force_unmount')):
+ errors.append(_('nfsrestart requires force_unmount to be enabled'))
return errors
def addNetfs(res, rname, model, **kw):
11 years, 7 months
[luci] luci: Fix unfence display on node page
by Ryan McCabe
commit cc1452e01504725f01bc5636f5e17335d5d1fad0
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Oct 8 09:52:45 2012 -0400
luci: Fix unfence display on node page
When looking for <device> blocks that match <unfence> blocks, only
compare attributes that are pertinent for determining whether
one blocks corresponds to the other.
Resolves: rhbz#815666
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/lib/ClusterConf/Device.py | 27 ++++++++++++++++++++++++++-
luci/lib/ClusterConf/FenceDeviceAttr.py | 2 ++
luci/templates/fence_instances.html | 31 +++++++++++++++++++++++++++----
luci/validation/validate_fence.py | 4 ++--
4 files changed, 57 insertions(+), 7 deletions(-)
---
diff --git a/luci/lib/ClusterConf/Device.py b/luci/lib/ClusterConf/Device.py
index a991318..12758c5 100644
--- a/luci/lib/ClusterConf/Device.py
+++ b/luci/lib/ClusterConf/Device.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2010 Red Hat, Inc.
+# Copyright (C) 2006-2012 Red Hat, Inc.
#
# This program is free software; you can redistribute
# it and/or modify it under the terms of version 2 of the
@@ -24,6 +24,31 @@ class Device(TagObject):
def setAgentType(self, agent_type):
self.agent_type = agent_type
+ def matchesUnfence(self, unfence):
+ if self.getName() != unfence.getName():
+ return False
+
+ agent_type = self.getAgentType()
+ if agent_type == 'fence_scsi':
+ # key overrides nodename
+ key_attr = self.getAttribute('key')
+ if key_attr:
+ if key_attr == unfence.getAttribute('key'):
+ return True
+ else:
+ if self.getAttribute('nodename') == unfence.getAttribute('nodename'):
+ return True
+ elif (agent_type == 'fence_sanbox2'
+ or agent_type == 'fence_brocade'
+ or agent_type == 'fence_mcdata'):
+ if self.getAttribute('port') == unfence.getAttribute('port'):
+ return True
+ elif agent_type == 'fence_egenera':
+ if (self.getAttribute('pserver') == unfence.getAttribute('pserver')
+ and self.getAttribute('lpan') == unfence.getAttribute('lpan')):
+ return True
+ return False
+
def hasNativeOptionSet(self):
return self.has_native_option_set
diff --git a/luci/lib/ClusterConf/FenceDeviceAttr.py b/luci/lib/ClusterConf/FenceDeviceAttr.py
index 91f8e9e..9775b00 100644
--- a/luci/lib/ClusterConf/FenceDeviceAttr.py
+++ b/luci/lib/ClusterConf/FenceDeviceAttr.py
@@ -28,6 +28,7 @@ FENCE_OPTS = {
'fence_scsi': 'SCSI Reservation Fencing',
'fence_ilo': 'HP iLO Device',
'fence_ipmilan': 'IPMI Lan',
+ 'fence_ipdu': 'IBM iPDU',
'fence_drac': 'Dell DRAC',
'fence_drac5': 'Dell DRAC 5',
'fence_rsa': 'IBM RSA II Device',
@@ -78,6 +79,7 @@ FENCE_SHARED = {
'fence_eps': True,
'fence_ibmblade': True,
'fence_ifmib': True,
+ 'fence_ipdu': True,
'fence_intelmodular': True,
'fence_virsh': True,
'fence_rhevm': True,
diff --git a/luci/templates/fence_instances.html b/luci/templates/fence_instances.html
index c619982..9bfada3 100644
--- a/luci/templates/fence_instances.html
+++ b/luci/templates/fence_instances.html
@@ -73,6 +73,15 @@
py:attrs="cur_fence_inst and {'value': cur_fence_inst.getAttribute('pserver')}"/>
</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="on" />
+ </td>
+ </tr>
<tr><td colspan="2">
<div>
<input type="button" name="remove_fence" value="Remove this instance"
@@ -347,7 +356,7 @@
<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" />
+ <input type="hidden" name="unfence_action" value="on" />
</td>
</tr>
<tr><td colspan="2">
@@ -404,7 +413,7 @@
<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" />
+ <input type="hidden" name="unfence_action" value="on" />
</td>
</tr>
<tr><td colspan="2">
@@ -437,7 +446,7 @@
<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" />
+ <input type="hidden" name="unfence_action" value="on" />
</td>
</tr>
<tr><td colspan="2">
@@ -1002,6 +1011,21 @@
<input type="hidden" name="unfence_action" value="on" />
</td>
</tr>
+ <tr>
+ <td>Node name</td>
+ <td>
+ <input py:if="cur_fence_inst" type="text" class="text" name="nodename"
+ value="${cur_fence_inst.getAttribute('nodename')}"/>
+ <input py:if="not cur_fence_inst and kw.get('nodename')" type="text" class="text" name="nodename" value="${kw.get('nodename')}"/>
+ </td>
+ </tr>
+ <tr>
+ <td>Key for current action (overrides node name)</td>
+ <td>
+ <input type="text" class="text" name="key"
+ py:attrs="cur_fence_inst and {'value': cur_fence_inst.getAttribute('key')} or {}"/>
+ </td>
+ </tr>
<tr><td colspan="2">
<div>
<input type="button" name="remove_fence" value="Remove this instance"
@@ -1009,7 +1033,6 @@
</div>
</td></tr>
</table>
- <input py:if="kw.get('nodename')" type="hidden" name="nodename" value="${kw['nodename']}" />
<input type="hidden" name="fence_type" value="fence_scsi" />
<input type="hidden" name="fence_instance" value="1" />
<input type="hidden" name="parent_fencedev"
diff --git a/luci/validation/validate_fence.py b/luci/validation/validate_fence.py
index db9161a..2ea032e 100644
--- a/luci/validation/validate_fence.py
+++ b/luci/validation/validate_fence.py
@@ -300,7 +300,6 @@ def val_vmware_fd(fencedev, fence_name, **kw):
def val_scsi_fd(fencedev, fence_name, **kw):
params = (
('devices', False),
- ('key', False),
('aptpl', False),
)
@@ -1012,6 +1011,7 @@ def val_intelmodular_fi(fenceinst, parent_name, **kw):
def val_scsi_fi(fenceinst, parent_name, **kw):
params = (
('nodename', False),
+ ('key', False),
)
errors = config_fence_attr(params, fenceinst, parent_name, **kw)
@@ -1244,7 +1244,7 @@ def getFenceInfo(model, nodename):
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:
+ if instance.matchesUnfence(child_device):
unfencing_flag = True
break
break
11 years, 7 months
[luci] luci: More fixes for resource/service/failover naming
by Ryan McCabe
commit c798dea0c1d022ea211ef9429ab0e4001f925cd8
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Oct 8 09:51:05 2012 -0400
luci: More fixes for resource/service/failover naming
Fix navigation to resources, services, and failover domains
whose names start with '/' or contain consecutive '/' chars.
Resolves: rhbz#807344
Signed-off-by: Ryan McCabe <rmccabe(a)redhat.com>
luci/controllers/cluster.py | 77 +++++++++++++++++++++---------
luci/templates/failover.html | 6 ++-
luci/templates/resource.html | 2 +-
luci/templates/service.html | 6 +-
luci/validation/validate_cluster_prop.py | 1 +
5 files changed, 65 insertions(+), 27 deletions(-)
---
diff --git a/luci/controllers/cluster.py b/luci/controllers/cluster.py
index d9011fc..af6b1cb 100644
--- a/luci/controllers/cluster.py
+++ b/luci/controllers/cluster.py
@@ -494,7 +494,7 @@ class IndividualClusterController(BaseController):
redirect(tmpl_context.cluster_url + kw.get('name'))
@expose("luci.templates.resource")
- def resources(self, *args):
+ def resources(self, *args, **kwargs):
try:
permission_view(self.name)
except NotAuthorizedError, e:
@@ -508,11 +508,22 @@ class IndividualClusterController(BaseController):
resourcename = '/'.join([unquote_plus(a) for a in args])
else:
resourcename = None
+
+ if 'name' in request.params:
+ resourcename = request.params['name']
+
+ try:
+ self.get_model()
+ self.model.getResourceByName(resourcename)
+ except KeyError, e:
+ resourcename=None
+
return dict(page='nodes', name=resourcename, base_url=base_url, resources_cmd=resources_cmd)
@expose("luci.templates.resource")
def resources_cmd(self, command=None, **kw):
tmpl_context.cluster_url = '/cluster/%s/resources' % self.name
+ redir_fmt = '%s?name=%s'
try:
permission_config(self.name)
@@ -561,6 +572,7 @@ class IndividualClusterController(BaseController):
status='info')
rh.update_cluster_conf(self.model)
+ redirect(tmpl_context.cluster_url)
elif command in ("Create", "Edit"):
if command == 'Create':
cur_action = _('Created')
@@ -579,25 +591,27 @@ class IndividualClusterController(BaseController):
kw['address'] = address
kw.pop('address_nominal', None)
kw.pop('address_mask', None)
- vret = validate_resource_form(self.model, **kw)
- if vret[0] is True:
# For IP resources there is no name, just an IP Address
# and to make IP addresses work you need to add a .html
- redir_fmt = '%s/%s.html'
- if res_type == 'ip':
- res_name = kw.get('address')
- else:
- res_name = quote_plus(kw.get('resourcename'))
+ res_name = kw.get('address')
+ else:
+ res_name = kw.get('resourcename')
+
+ vret = validate_resource_form(self.model, **kw)
+ if vret[0] is True:
log.info('User "%s" %s global resource "%s" in cluster "%s"'
% (self.username, cur_action, res_name, self.name))
flash(_('%s global resource "%s"') % (cur_action, res_name))
rh.update_cluster_conf(self.model)
- redirect(redir_fmt % (tmpl_context.cluster_url, res_name))
+ redirect(redir_fmt
+ % (tmpl_context.cluster_url, quote_plus(res_name)))
else:
msgs = vret[1].get('errors')
if msgs and len(msgs) > 0:
flash(', '.join(msgs), status="error")
- redirect(tmpl_context.cluster_url)
+ if command != 'Create':
+ redirect(redir_fmt
+ % (tmpl_context.cluster_url, quote_plus(res_name)))
else:
log.error('User "%s" submitted unknown command "%s" for resource "%s" from cluster "%s"' % (self.username, command, ', '.join(cur_list), self.name))
flash(_('An unknown command "%s" was given for resources "%s"')
@@ -606,7 +620,7 @@ class IndividualClusterController(BaseController):
redirect(tmpl_context.cluster_url)
@expose("luci.templates.service")
- def services(self, *args):
+ def services(self, *args, **kwargs):
try:
permission_view(self.name)
except NotAuthorizedError, e:
@@ -617,12 +631,16 @@ class IndividualClusterController(BaseController):
services_cmd = '/cluster/%s/services_cmd' % self.name
if args:
- if len(args) > 1:
+ if len(args) >= 1:
servicename = '/'.join([unquote_plus(a) for a in args])
if request.response_ext:
servicename = '%s%s' % (servicename, request.response_ext)
else:
servicename = None
+
+ if 'name' in request.params:
+ servicename = request.params['name']
+
return dict(page='nodes', name=servicename, base_url=base_url, services_cmd=services_cmd)
@expose("luci.templates.service")
@@ -686,7 +704,8 @@ class IndividualClusterController(BaseController):
vm_name = cur_list[0]
if not preferred_node:
flash(_('No destination node was given for the migration of VM "%s"') % vm_name, status="error")
- redirect(tmpl_context.cluster_url)
+ redirect('%s?name=%s'
+ % (tmpl_context.cluster_url, quote_plus(vm_name)))
log.info('User "%s" migrated VM "%s" in cluster "%s to node %s"'
% (self.username, vm_name, self.name, preferred_node))
flash(_('Migrating VM "%s" to node "%s"') % (vm_name, preferred_node))
@@ -751,19 +770,26 @@ class IndividualClusterController(BaseController):
msgs = vret[1].get('errors')
if msgs and len(msgs) > 0:
flash(', '.join(msgs), status="error")
- redirect('%s/%s' % (tmpl_context.cluster_url, quote_plus(svc_name)))
+ if command != 'Create':
+ redirect('%s?name=%s'
+ % (tmpl_context.cluster_url, quote_plus(svc_name)))
+ else:
+ redirect(tmpl_context.cluster_url)
+
else:
log.error('User "%s" submitted unknown command "%s" for service "%s" from cluster "%s"' % (self.username, command, ', '.join(cur_list), self.name))
flash(_('An unknown command "%s" was given for services "%s"')
% (command, ', '.join(cur_list)),
status='error')
+
if len(cur_list) != 1:
redirect(tmpl_context.cluster_url)
else:
- redirect(tmpl_context.cluster_url + '/' + quote_plus(cur_list[0]))
+ redirect('%s?name=%s'
+ % (tmpl_context.cluster_url, quote_plus(cur_list[0])))
@expose("luci.templates.failover")
- def failovers(self, *args):
+ def failovers(self, *args, **kwargs):
failovers_cmd = '/cluster/%s/failovers_cmd' % self.name
try:
@@ -779,6 +805,10 @@ class IndividualClusterController(BaseController):
failovername = args[0]
else:
failovername = None
+
+ if 'name' in request.params:
+ failovername = request.params['name']
+
return dict(page='nodes', name=failovername, base_url = '/cluster/' + self.name + '/failovers', failovers_cmd=failovers_cmd)
@expose("luci.templates.failover")
@@ -801,11 +831,11 @@ class IndividualClusterController(BaseController):
if 'MultiAction' in kw:
kw["name"] = ""
command = kw['MultiAction']
- cur_list = [x for x in kw if kw[x] == 'on' in kw[x]]
+ cur_list = [unquote_plus(x) for x in kw if kw[x] == 'on' in kw[x]]
else:
obj_name = kw.get('name')
if obj_name:
- cur_list = [ obj_name ]
+ cur_list = [ unquote_plus(obj_name) ]
if len(cur_list) < 1 and command != 'create':
flash(_('No failover domains were selected'),
@@ -840,7 +870,8 @@ class IndividualClusterController(BaseController):
msgs = vret[1].get('errors')
if msgs and len(msgs) > 0:
flash(', '.join(msgs), status="error")
- redirect(tmpl_context.cluster_url + '/' + kw.get('name'))
+ redirect('%s?name=%s'
+ % (tmpl_context.cluster_url, quote_plus(cur_list[0])))
elif command == 'update_properties':
vret = vcp.validate_fdom_prop_form(self.model, **kw)
if vret[0] is True:
@@ -852,20 +883,22 @@ class IndividualClusterController(BaseController):
msgs = vret[1].get('errors')
if msgs and len(msgs) > 0:
flash(', '.join(msgs), status="error")
- redirect(tmpl_context.cluster_url + '/' + kw.get('name'))
+ redirect('%s?name=%s'
+ % (tmpl_context.cluster_url, quote_plus(cur_list[0])))
elif command == 'create':
vret = vcp.validate_fdom_create_form(self.model, **kw)
if vret[0] is True:
log.info('User "%s" created failover domain "%s" in cluster "%s"'
% (self.username, kw.get('fdom_name'), self.name))
flash(_('Creating failover domain "%s"') % kw.get('fdom_name'))
-
rh.update_cluster_conf(self.model)
+ redirect('%s?name=%s'
+ % (tmpl_context.cluster_url, quote_plus(kw.get('fdom_name').strip())))
else:
msgs = vret[1].get('errors')
if msgs and len(msgs) > 0:
flash(', '.join(msgs), status="error")
- redirect(tmpl_context.cluster_url)
+ redirect(tmpl_context.cluster_url)
else:
log.error('User "%s" submitted unknown command "%s" for failover domains "%s" from cluster "%s"'
% (self.username, command, ', '.join(cur_list), self.name))
diff --git a/luci/templates/failover.html b/luci/templates/failover.html
index 4e512b3..297a7f8 100644
--- a/luci/templates/failover.html
+++ b/luci/templates/failover.html
@@ -6,6 +6,10 @@
<xi:include href="master.html" />
+<?python
+ from urllib import quote_plus
+?>
+
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
<title>${title()}</title>
@@ -48,7 +52,7 @@
onclick="update_multi_action(this)" class="MultiActionItem"/>
</td>
<td class="icon"></td>
- <td class="main_id"><a href="${tg.url(base_url + '/' + entity_name)}">${entity_name}</a></td>
+ <td class="main_id"><a href="${tg.url(base_url + '?name=' + quote_plus(entity_name))}">${entity_name}</a></td>
<td class="fdom_tlist_prioritizied">
<py:choose test="failover_data.getOrdered()">
<img py:when="True" src="${tg.url('/images/check-11.png')}" alt="*" />
diff --git a/luci/templates/resource.html b/luci/templates/resource.html
index 47173cc..d91e09c 100644
--- a/luci/templates/resource.html
+++ b/luci/templates/resource.html
@@ -52,7 +52,7 @@
py:attrs="refcount != 1 and {'disabled':'disabled'} or {}"/>
</td>
<td class="main_id">
- <a href="${tg.url(base_url + '/' + quote_plus(entity_name) + '.html')}"><span class="entity_ok">${entity_name}</span></a>
+ <a href="${tg.url(base_url + '?name=' + quote_plus(entity_name))}"><span class="entity_ok">${entity_name}</span></a>
</td>
<td class="resource_tlist_type">
${resource_data.getResourceType()}
diff --git a/luci/templates/service.html b/luci/templates/service.html
index a5e18db..ef76bea 100644
--- a/luci/templates/service.html
+++ b/luci/templates/service.html
@@ -65,7 +65,7 @@
<py:when test="'true'">
<td class="icon"></td>
<td class="main_id">
- <a href="${tg.url(base_url + '/' + quote_plus(entity_name))}">
+ <a href="${tg.url(base_url + '?name=' + quote_plus(entity_name))}">
<span class="entity_ok">${entity_name}</span>
</a>
</td>
@@ -84,7 +84,7 @@
<img src="${tg.url('/images/exclamation.png')}" alt="Service has a problem." />
</td>
<td class="main_id">
- <a href="${tg.url(base_url + '/' + quote_plus(entity_name))}">
+ <a href="${tg.url(base_url + '?name=' + quote_plus(entity_name))}">
<span class="entity_fail">${entity_name}</span>
</a>
</td>
@@ -102,7 +102,7 @@
<img src="${tg.url('/images/question.png')}" alt="Internal error; file a bug report." />
</td>
<td class="main_id">
- <a href="${tg.url(base_url + '/' + quote_plus(entity_name))}">
+ <a href="${tg.url(base_url + '?name=' + quote_plus(entity_name))}">
<span class="entity_ok">${entity_name}</span>
</a>
</td>
diff --git a/luci/validation/validate_cluster_prop.py b/luci/validation/validate_cluster_prop.py
index dd84092..a754d40 100644
--- a/luci/validation/validate_cluster_prop.py
+++ b/luci/validation/validate_cluster_prop.py
@@ -53,6 +53,7 @@ def validate_fdom_create_form(model, **kw):
if not fdom_name or fdom_name.isspace():
errors.append(_('No name was given for this failover domain'))
return (False, {'errors': errors})
+ fdom_name = fdom_name.strip()
if model.getFailoverDomainByName(fdom_name):
errors.append(_('A failover domain named "%s" already exists') % fdom_name)
11 years, 7 months