From: rmccabe@sourceware.org <rmccabe@sourceware.org>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] conga ./clustermon.spec.in.in ./conga.spec.in. ...
Date: 29 Jul 2008 19:47:15 -0000 [thread overview]
Message-ID: <20080729194715.12808.qmail@sourceware.org> (raw)
CVSROOT: /cvs/cluster
Module name: conga
Changes by: rmccabe at sourceware.org 2008-07-29 19:47:07
Modified files:
. : clustermon.spec.in.in conga.spec.in.in
luci/cluster : cluster_config-macros cluster_svc-macros
fence-macros validate_config_qdisk.js
luci/plone-custom: conga.js
luci/site/luci/Extensions: HelperFunctions.py LuciValidation.py
LuciZopeClusterPortal.py
StorageReport.py cluster_adapters.py
conga_constants.py
luci/storage : form-macros
ricci/modules/cluster/clumon: REDHAT-CLUSTER-MIB
ricci/modules/rpm: PackageHandler.cpp
ricci/modules/service: ServiceManager.cpp
ricci/modules/storage: LVM.cpp
ricci/modules/virt: Makefile Virt.cpp
ricci/ricci : DBusController.cpp
ricci/ricci/d-bus: ricci.oddjob.conf
ricci/test_suite/cluster: vm_list.xml
Log message:
Forward port fixes from RHEL5
Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/clustermon.spec.in.in.diff?cvsroot=cluster&r1=1.45&r2=1.46
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/conga.spec.in.in.diff?cvsroot=cluster&r1=1.99&r2=1.100
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/cluster_config-macros.diff?cvsroot=cluster&r1=1.4&r2=1.5
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/cluster_svc-macros.diff?cvsroot=cluster&r1=1.7&r2=1.8
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/fence-macros.diff?cvsroot=cluster&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/cluster/validate_config_qdisk.js.diff?cvsroot=cluster&r1=1.12&r2=1.13
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/plone-custom/conga.js.diff?cvsroot=cluster&r1=1.14&r2=1.15
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/HelperFunctions.py.diff?cvsroot=cluster&r1=1.15&r2=1.16
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/LuciValidation.py.diff?cvsroot=cluster&r1=1.10&r2=1.11
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/LuciZopeClusterPortal.py.diff?cvsroot=cluster&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/StorageReport.py.diff?cvsroot=cluster&r1=1.30&r2=1.31
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/cluster_adapters.py.diff?cvsroot=cluster&r1=1.283&r2=1.284
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/site/luci/Extensions/conga_constants.py.diff?cvsroot=cluster&r1=1.50&r2=1.51
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/luci/storage/form-macros.diff?cvsroot=cluster&r1=1.31&r2=1.32
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/modules/cluster/clumon/REDHAT-CLUSTER-MIB.diff?cvsroot=cluster&r1=1.2&r2=1.3
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/modules/rpm/PackageHandler.cpp.diff?cvsroot=cluster&r1=1.24&r2=1.25
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/modules/service/ServiceManager.cpp.diff?cvsroot=cluster&r1=1.20&r2=1.21
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/modules/storage/LVM.cpp.diff?cvsroot=cluster&r1=1.13&r2=1.14
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/modules/virt/Makefile.diff?cvsroot=cluster&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/modules/virt/Virt.cpp.diff?cvsroot=cluster&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/DBusController.cpp.diff?cvsroot=cluster&r1=1.18&r2=1.19
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/ricci/d-bus/ricci.oddjob.conf.diff?cvsroot=cluster&r1=1.1&r2=1.2
http://sourceware.org/cgi-bin/cvsweb.cgi/conga/ricci/test_suite/cluster/vm_list.xml.diff?cvsroot=cluster&r1=1.1&r2=1.2
--- conga/clustermon.spec.in.in 2008/06/06 16:41:52 1.45
+++ conga/clustermon.spec.in.in 2008/07/29 19:46:59 1.46
@@ -27,7 +27,7 @@
Source0: %{name}-%{version}.tar.gz
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-BuildRequires: cman-devel libvirt-devel
+BuildRequires: cman-devel
BuildRequires: glibc-devel gcc-c++ libxml2-devel
BuildRequires: openssl-devel dbus-devel pam-devel pkgconfig
BuildRequires: net-snmp-devel tog-pegasus-devel
@@ -45,6 +45,7 @@
--docdir=%{_docdir} \
--pegasus_providers_dir=%{PEGASUS_PROVIDERS_DIR} \
--include_zope_and_plone=no
+
make %{?_smp_mflags} clustermon
%install
@@ -56,7 +57,6 @@
-
### cluster module ###
--- conga/conga.spec.in.in 2008/06/13 18:38:49 1.99
+++ conga/conga.spec.in.in 2008/07/29 19:47:00 1.100
@@ -31,9 +31,14 @@
%endif
Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+%define virt_support 0
+
+%ifarch i386 x86_64 ia64
+%define virt_support 1
+%endif
+
BuildRequires: python-devel >= 2.4.1
BuildRequires: glibc-devel gcc-c++ libxml2-devel sed
-BuildRequires: cman-devel
BuildRequires: cyrus-sasl-devel >= 2.1
BuildRequires: openssl-devel dbus-devel pkgconfig file
@@ -57,9 +62,16 @@
%endif
%build
+%if %{virt_support}
%configure --arch=%{_arch} \
--docdir=%{_docdir} \
- --include_zope_and_plone=%{include_zope_and_plone}
+ --include_zope_and_plone=%{include_zope_and_plone} --VIRT_SUPPORT=1
+%else
+%configure --arch=%{_arch} \
+ --docdir=%{_docdir} \
+ --include_zope_and_plone=%{include_zope_and_plone} --VIRT_SUPPORT=0
+%endif
+
make %{?_smp_mflags} conga
%install
@@ -199,10 +211,16 @@
Requires: initscripts
Requires: oddjob dbus openssl pam cyrus-sasl >= 2.1
Requires: sed util-linux
-Requires: modcluster >= 0.10.0
+Requires: modcluster >= 0.12.0
# modreboot
+# modvirt
+
+%if %{virt_support}
+BuildRequires: libvirt-devel
+%endif
+
# modrpm
# modstorage
@@ -254,13 +272,14 @@
%config(noreplace) %{_sysconfdir}/dbus-1/system.d/ricci-modlog.systembus.conf
%{_libexecdir}/ricci-modlog
+# modvirt
+%config(noreplace) %{_sysconfdir}/oddjobd.conf.d/ricci-modvirt.oddjob.conf
+%config(noreplace) %{_sysconfdir}/dbus-1/system.d/ricci-modvirt.systembus.conf
+ %{_libexecdir}/ricci-modvirt
+
%pre -n ricci
-if ! /bin/grep ^ricci\:x /etc/group >&/dev/null; then
- /usr/sbin/groupadd -r -f ricci >&/dev/null
-fi
-if ! /bin/grep ^ricci\:x /etc/passwd >&/dev/null; then
- /usr/sbin/useradd -r -M -s /sbin/nologin -d /var/lib/ricci -g ricci ricci >&/dev/null
-fi
+getent group ricci >/dev/null || groupadd -r ricci
+getent passwd ricci >/dev/null || useradd -r -M -g ricci -d /var/lib/ricci -s /sbin/nologin -c "ricci daemon user" ricci
exit 0
%post -n ricci
--- conga/luci/cluster/cluster_config-macros 2008/02/08 21:47:55 1.4
+++ conga/luci/cluster/cluster_config-macros 2008/07/29 19:47:02 1.5
@@ -715,21 +715,39 @@
</td>
</tr>
- <tr class="systemsTable">
- <td class="systemsTable">Device</td>
- <td class="systemsTable">
- <input type="text" name="device"
- tal:attributes="value clusterinfo/device | nothing" />
- </td>
- </tr>
-
- <tr class="systemsTable">
- <td class="systemsTable">Label</td>
- <td class="systemsTable">
- <input type="text" name="label"
- tal:attributes="value clusterinfo/label | nothing" />
- </td>
- </tr>
+
+ <tr class="systemsTable"><td colspan="2">
+ <table class="systemsTable">
+ <tr class="systemsTable">
+ <td class="systemsTable">
+ <input type="radio" name="qdisk_dev_label"
+ onclick="disable_text_field(this.form.label, this.form.device)">Label
+ </td>
+ <td class="systemsTable">
+ <input type="text" name="label" id="qdisk_label"
+ onfocus="disable_text_field(this.form.label, this.form.device);this.form.qdisk_dev_label[0].checked='checked';"
+ tal:attributes="
+ disabled python:(clusterinfo.get('label') or not clusterinfo.get('device')) and '' or 'disabled';
+ checked python:(clusterinfo.get('label') or not clusterinfo.get('label')) and 'checked' or '';
+ value clusterinfo/label | nothing" />
+ </td>
+ </tr>
+ <tr class="systemsTable">
+ <td class="systemsTable">
+ <input type="radio" name="qdisk_dev_label"
+ onclick="disable_text_field(this.form.device, this.form.label)">Device (deprecated)
+ </td>
+ <td class="systemsTable">
+ <input type="text" name="device" id="qdisk_device"
+ onfocus="disable_text_field(this.form.device, this.form.label);this.form.qdisk_dev_label[1].checked='checked';"
+ tal:attributes="
+ disabled python:clusterinfo.get('device') and '' or 'disabled';
+ checked python:clusterinfo.get('device') and 'checked' or '';
+ value clusterinfo/device | nothing" />
+ </td>
+ </tr>
+ </table>
+ </td></tr>
</table>
</div>
--- conga/luci/cluster/cluster_svc-macros 2008/03/06 21:27:16 1.7
+++ conga/luci/cluster/cluster_svc-macros 2008/07/29 19:47:02 1.8
@@ -46,7 +46,7 @@
class python: 'cluster service ' + (running and 'running' or 'stopped')"
tal:content="svc/name" />
<tal:block tal:condition="exists:svc/is_vm">
- (virtual service)
+ (virtual machine service)
</tal:block>
</td>
@@ -156,46 +156,8 @@
<p class="reshdr">Create a Virtual Machine Service</p>
</td></tr>
<tfoot class="systemsTable">
- <tr class="systemsTable">
- <td>Automatically start this service</td>
- <td>
- <input type="checkbox" name="autostart" checked="checked">
- </td>
- </tr>
- <tr class="systemsTable">
- <td>Run exclusive</td>
- <td>
- <input type="checkbox" name="exclusive">
- </td>
- </tr>
- <tr class="systemsTable">
- <td>Failover Domain</td>
- <td>
- <select name="domain">
- <option value="" selected="selected">None</option>
- <tal:block tal:repeat="f python:here.get_fdom_names(modelb)">
- <option tal:content="f"
- tal:attributes="value f" />
- </tal:block>
- </select>
- </td>
- </tr>
-
- <tr class="systemsTable">
- <td>Recovery policy</td>
- <td>
- <select name="recovery">
- <option value="">Select a recovery policy</option>
- <option name="relocate" value="relocate">Relocate</option>
- <option name="restart" value="restart">Restart</option>
- <option name="disable" value="disable">Disable</option>
- </select>
- </td>
- </tr>
-
<tr class="systemsTable"
tal:condition="exists:clusterinfo/vm_migration_choice">
-
<td>Migration type</td>
<td>
<select name="migration_type">
@@ -205,6 +167,8 @@
</td>
</tr>
+ <tal:block metal:use-macro="here/cluster_svc-macros/macros/failover-prefs-macro" />
+
<tr class="systemsTable"><td colspan="2">
<div class="hbSubmit">
<input type="submit" value="Create Virtual Machine Service" />
@@ -228,7 +192,7 @@
<div metal:define-macro="vmconfig-form">
<form method="post" action=""
- tal:define="vminfo python:here.getVMInfo(modelb, request)">
+ tal:define="sinfo python:here.getVMInfo(modelb, request)">
<input type="hidden" name="clustername"
tal:attributes="value request/clustername | nothing" />
@@ -237,14 +201,14 @@
tal:attributes="value request/pagetype | nothing" />
<input type="hidden" name="oldname"
- tal:attributes="value vminfo/name | nothing" />
+ tal:attributes="value sinfo/name | nothing" />
<div class="service_comp_list">
<table class="systemsTable">
<thead class="systemsTable">
<tr class="systemsTable">
<td class="systemsTable">
- <p class="reshdr">Properties for <tal:block tal:replace="vminfo/name | string:virtual machine service"/></p>
+ <p class="reshdr">Properties for <tal:block tal:replace="sinfo/name | string:virtual machine service"/></p>
</td>
</tr>
@@ -313,66 +277,21 @@
</thead>
<tfoot class="systemsTable">
- <tr class="systemsTable">
- <td>Automatically start this service</td>
- <td>
- <input type="checkbox" name="autostart"
- tal:attributes="checked python: ('autostart' in vminfo and vminfo['autostart'] != '0') and 'checked' or ''" />
- </td>
- </tr>
- <tr class="systemsTable">
- <td>Run exclusive</td>
- <td>
- <input type="checkbox" name="exclusive"
- tal:attributes="checked python: ('exclusive' in vminfo and vminfo['exclusive'] != '0') and 'checked' or ''" />
- </td>
- </tr>
- <tr class="systemsTable">
- <td>Failover Domain</td>
- <td>
- <select name="domain">
- <option value="" tal:content="string:None"
- tal:attributes="selected python: (not 'domain' in vminfo or not vminfo['domain']) and 'selected' or ''" />
- <tal:block tal:repeat="f python:here.get_fdom_names(modelb)">
- <option tal:content="f"
- tal:attributes="
- value f;
- selected python: ('domain' in vminfo and vminfo['domain'] == f) and 'selected' or ''" />
- </tal:block>
- </select>
- </td>
- </tr>
- <tr class="systemsTable">
- <td>Recovery policy</td>
- <td>
- <select name="recovery">
- <option value="">Select a recovery policy</option>
- <option name="relocate" value="relocate"
- tal:content="string:Relocate"
- tal:attributes="selected python: ('recovery' in vminfo and vminfo['recovery'] == 'relocate') and 'selected' or ''" />
- <option name="restart" value="restart"
- tal:content="string:Restart"
- tal:attributes="selected python: ('recovery' in vminfo and vminfo['recovery'] == 'restart') and 'selected' or ''" />
- <option name="disable" value="disable"
- tal:content="string:Disable"
- tal:attributes="selected python: ('recovery' in vminfo and vminfo['recovery'] == 'disable') and 'selected' or ''" />
- </select>
- </td>
- </tr>
-
<tr class="systemsTable"
- tal:condition="exists:vminfo/vm_migration_choice">
+ tal:condition="exists:sinfo/vm_migration_choice">
<td>Migration type</td>
<td>
<select name="migration_type">
<option value="live" tal:content="string:Live"
- tal:attributes="selected python:('migrate' not in vminfo or vminfo['migrate'] != 'pause') and 'selected' or ''" />
+ tal:attributes="selected python:(sinfo.get('migrate') != 'pause') and 'selected' or ''" />
<option value="pause" tal:content="string:Pause"
- tal:attributes="selected python:('migrate' in vminfo and vminfo['migrate'] == 'pause') and 'selected' or ''" />
+ tal:attributes="selected python:(sinfo.get('migrate') == 'pause') and 'selected' or ''" />
</select>
</td>
</tr>
+
+ <tal:block metal:use-macro="here/cluster_svc-macros/macros/failover-prefs-macro" />
<tr class="systemsTable"><td colspan="2">
<div class="hbSubmit">
@@ -386,14 +305,14 @@
<td><span class="cluster_help" title="e.g., guest1 if the VM config file is@/etc/xen/guest1">Virtual machine name</span></td>
<td>
<input type="text" name="vmname"
- tal:attributes="value vminfo/name | nothing" />
+ tal:attributes="value sinfo/name | nothing" />
</td>
</tr>
<tr class="systemsTable">
<td><span class="cluster_help" title="e.g., /etc/xen/">Path to VM configuration files</span></td>
<td>
<input type="text" name="vmpath"
- tal:attributes="value vminfo/path | nothing" />
+ tal:attributes="value sinfo/path | nothing" />
</td>
</tr>
</tbody>
@@ -427,43 +346,7 @@
<input type="text" length="20" name="service_name" value="" />
</td>
</tr>
- <tr class="systemsTable">
- <td class="systemsTable">
- Automatically start this service
- </td>
- <td class="systemsTable">
- <input type="checkbox" name="autostart" checked="checked" />
- </td>
- </tr>
- <tr class="systemsTable">
- <td class="systemsTable">Run exclusive</td>
- <td class="systemsTable">
- <input type="checkbox" name="exclusive">
- </td>
- </tr>
- <tr class="systemsTable">
- <td class="systemsTable">Failover Domain</td>
- <td class="systemsTable">
- <select name="domain">
- <option value="" selected="selected">None</option>
- <tal:block tal:repeat="f sinfo/fdoms">
- <option tal:content="f"
- tal:attributes="value f" />
- </tal:block>
- </select>
- </td>
- </tr>
- <tr class="systemsTable">
- <td class="systemsTable">Recovery policy</td>
- <td class="systemsTable">
- <select name="recovery">
- <option value="">Select a recovery policy</option>
- <option name="relocate" value="relocate">Relocate</option>
- <option name="restart" value="restart">Restart</option>
- <option name="disable" value="disable">Disable</option>
- </select>
- </td>
- </tr>
+ <tal:block metal:use-macro="here/cluster_svc-macros/macros/failover-prefs-macro" />
</table>
</form>
</div>
@@ -522,7 +405,7 @@
<div metal:define-macro="servicemigrate">
<script type="text/javascript">
- set_page_title('Luci ??? cluster ??? services ??? Migrate a virtual service');
+ set_page_title('Luci ??? cluster ??? services ??? Migrate a virtual machine service');
</script>
<tal:block tal:define="
@@ -625,6 +508,76 @@
</tal:block>
</div>
+<div metal:define-macro="failover-prefs-macro" tal:omit-tag="">
+ <tr>
+ <td>Automatically start this service</td>
+ <td>
+ <input type="checkbox" name="autostart"
+ tal:attributes="checked python:(sinfo and sinfo.get('autostart') and sinfo['autostart'].lower() != 'false') and 'checked'" />
+ </td>
+ </tr>
+
+ <tr>
+ <td>Run exclusive</td>
+ <td>
+ <input type="checkbox" name="exclusive"
+ tal:attributes="checked python:(sinfo and sinfo.get('exclusive')and sinfo.get('exclusive').lower() != 'false') and 'checked'" />
+ </td>
+ </tr>
+
+ <tr>
+ <td>Failover Domain</td>
+ <td>
+ <select name="domain">
+ <option value=""
+ tal:attributes="selected python:(not sinfo or not sinfo.get('domain')) and 'selected' or ''">None</option>
+ <tal:block tal:condition="exists:sinfo/fdoms">
+ <tal:block tal:repeat="f sinfo/fdoms">
+ <option tal:content="f" tal:attributes="
+ value f;
+ selected python:(sinfo and sinfo.get('domain') == f) and 'selected' or ''" />
+ </tal:block>
+ </tal:block>
+ </select>
+ </td>
+ </tr>
+
+ <tr class="systemsTable">
+ <td>Recovery policy</td>
+ <td>
+ <select name="recovery">
+ <option value="">Select a recovery policy</option>
+ <option name="relocate" value="relocate"
+ tal:content="string:Relocate"
+ tal:attributes="selected python:(sinfo and sinfo.get('recovery') == 'relocate') and 'selected' or ''" />
+ <option name="restart" value="restart"
+ tal:content="string:Restart"
+ tal:attributes="selected python:(sinfo and sinfo.get('recovery') == 'restart') and 'selected' or ''" />
+ <option name="disable" value="disable"
+ tal:content="string:Disable"
+ tal:attributes="selected python:(sinfo and sinfo.get('recovery') == 'disable') and 'selected' or ''" />
+ </select>
+ </td>
+ </tr>
+
+ <tr class="systemsTable">
+ <td class="systemsTable">
+ Maximum number of restart failures before relocating
+ </td>
+ <td class="systemsTable">
+ <input type="text" size="3" name="max_restarts"
+ tal:attributes="value sinfo/max_restarts|string:0" />
+ </td>
+ </tr>
+ <tr class="systemsTable">
+ <td class="systemsTable">Length of time in seconds after which to forget a restart</td>
+ <td class="systemsTable">
+ <input type="text" size="3" name="restart_expire_time"
+ tal:attributes="value sinfo/restart_expire_time|string:0" />
+ </td>
+ </tr>
+</div>
+
<div metal:define-macro="service-config-head-macro" tal:omit-tag="">
<script type="text/javascript"
src="/luci/homebase/homebase_common.js">
@@ -778,51 +731,9 @@
<div class="service_comp_list">
<form name="service_name_form">
<table class="rescfg">
- <tr>
- <td>Automatically start this service</td>
- <td><input type="checkbox" name="autostart"
- tal:attributes="checked python: ('autostart' in sinfo and sinfo['autostart'].lower() != 'false') and 'checked'" />
- </td>
- </tr>
- <tr>
- <td>Run exclusive</td>
- <td><input type="checkbox" name="exclusive"
- tal:attributes="checked python: ('exclusive' in sinfo and sinfo['exclusive'].lower() != 'false') and 'checked'" />
- </td>
- </tr>
- <tr>
- <td>Failover Domain</td>
- <td>
- <select name="domain">
- <option value=""
- tal:attributes="selected python: (not 'domain' in sinfo or not sinfo['domain']) and 'selected' or ''">None</option>
- <tal:block tal:repeat="f sinfo/fdoms">
- <option tal:content="f"
- tal:attributes="
- value f;
- selected python: ('domain' in sinfo and sinfo['domain'] == f) and 'selected' or ''" />
- </tal:block>
- </select>
- </td>
- </tr>
- <tr class="systemsTable">
- <td>Recovery policy</td>
- <td>
- <select name="recovery">
- <option value="">Select a recovery policy</option>
- <option name="relocate" value="relocate"
- tal:content="string:Relocate"
- tal:attributes="selected python: ('recovery' in sinfo and sinfo['recovery'] == 'relocate') and 'selected' or ''" />
- <option name="restart" value="restart"
- tal:content="string:Restart"
- tal:attributes="selected python: ('recovery' in sinfo and sinfo['recovery'] == 'restart') and 'selected' or ''" />
- <option name="disable" value="disable"
- tal:content="string:Disable"
- tal:attributes="selected python: ('recovery' in sinfo and sinfo['recovery'] == 'disable') and 'selected' or ''" />
- </select>
- </td>
- </tr>
+ <tal:block metal:use-macro="here/cluster_svc-macros/macros/failover-prefs-macro" />
</table>
+
<input type="hidden" name="service_name"
tal:attributes="value sinfo/name | string:1" />
</form>
--- conga/luci/cluster/fence-macros 2008/04/23 17:33:37 1.3
+++ conga/luci/cluster/fence-macros 2008/07/29 19:47:02 1.4
@@ -684,6 +684,13 @@
</td>
</tr>
<tr>
+ <td>Module Name</td>
+ <td>
+ <input name="modulename" type="text"
+ tal:attributes="value cur_fencedev/modulename | nothing" />
+ </td>
+ </tr>
+ <tr>
<td>
<span title="Full path to a script to generate fence password">Password Script (optional)</span>
</td>
--- conga/luci/cluster/validate_config_qdisk.js 2008/01/02 20:52:22 1.12
+++ conga/luci/cluster/validate_config_qdisk.js 2008/07/29 19:47:02 1.13
@@ -206,6 +206,9 @@
var no_label = !form.label || str_is_blank(form.label.value);
if (no_dev && no_label)
errors.push('You must give either a label or a device.');
+ if (!no_dev && !no_label) {
+ errors.push('You may not specify both a device and a label.');
+ }
var hnum = document.getElementById('num_heuristics');
if (hnum) {
--- conga/luci/plone-custom/conga.js 2008/06/10 14:50:53 1.14
+++ conga/luci/plone-custom/conga.js 2008/07/29 19:47:02 1.15
@@ -248,6 +248,12 @@
elem.parentNode.removeChild(elem);
}
+function disable_text_field(enable_obj, disable_obj) {
+ disable_obj.value = "";
+ disable_obj.disabled = "disabled";
+ enable_obj.disabled = "";
+}
+
function swap_tabs(new_label, cur_tab, new_tab) {
if (cur_tab == new_tab) {
return (cur_tab);
--- conga/luci/site/luci/Extensions/HelperFunctions.py 2008/06/06 16:41:52 1.15
+++ conga/luci/site/luci/Extensions/HelperFunctions.py 2008/07/29 19:47:03 1.16
@@ -9,7 +9,7 @@
import threading
def resolveOSType(os_str):
- if not os_str or os_str.find('Tikanga') != (-1) or os_str.find('Zod') != (-1) or os_str.find('Moonshine') != (-1) or os_str.find('Werewolf') != (-1) or os.str_find('Sulphur') != (-1):
+ if not os_str or os_str.find('Tikanga') != (-1) or os_str.find('Zod') != (-1) or os_str.find('Moonshine') != (-1) or os_str.find('Werewolf') != (-1) or os_str.find('Sulphur') != (-1):
return 'rhel5'
else:
return 'rhel4'
--- conga/luci/site/luci/Extensions/LuciValidation.py 2008/05/12 18:03:39 1.10
+++ conga/luci/site/luci/Extensions/LuciValidation.py 2008/07/29 19:47:03 1.11
@@ -268,7 +268,7 @@
def validate_clusvc_add(model, request):
errors = list()
- fvar = GetReqVars(request, [ 'form_xml', 'domain', 'recovery', 'svc_name', 'action' ])
+ fvar = GetReqVars(request, [ 'form_xml', 'domain', 'recovery', 'svc_name', 'action', 'max_restarts', 'restart_expire_time' ])
form_xml = fvar['form_xml']
if form_xml is None:
@@ -370,6 +370,26 @@
if recovery is not None and recovery != 'restart' and recovery != 'relocate' and recovery != 'disable':
errors.append('You entered an invalid recovery option: "%s" Valid options are "restart" "relocate" and "disable."')
+ if recovery == 'restart':
+ max_restarts = None
+ if fvar['max_restarts']:
+ try:
+ max_restarts = int(fvar['max_restarts'])
+ if max_restarts < 0:
+ raise ValueError, 'must be greater than 0'
+ except Exception, e:
+ errors.append('Maximum restarts must be a number greater than or equal to 0')
+ max_restarts = None
+ restart_expire_time = None
+ if fvar['restart_expire_time']:
+ try:
+ restart_expire_time = int(fvar['restart_expire_time'])
+ if restart_expire_time < 0:
+ raise ValueError, 'must be greater than 0'
+ except Exception, e:
+ errors.append('Restart expire time must be a number greater than or equal to 0')
+ restart_expire_time = None
+
service_name = fvar['svc_name']
if service_name is None:
if LUCI_DEBUG_MODE is True:
@@ -440,6 +460,11 @@
new_service.addAttribute('domain', fdom)
if recovery:
new_service.addAttribute('recovery', recovery)
+ if max_restarts is not None:
+ new_service.addAttribute('max_restarts', str(max_restarts))
+ if restart_expire_time is not None:
+ new_service.addAttribute('restart_expire_time', str(restart_expire_time))
+
new_service.addAttribute('exclusive', str(exclusive))
if autostart is not None:
new_service.attr_hash['autostart'] = autostart
@@ -725,6 +750,8 @@
if not device and not label:
errors.append('No Device or Label value was given')
+ if device and label:
+ errors.append('You may not specify both device and label')
num_heuristics = 0
try:
@@ -1058,7 +1085,7 @@
def validate_vmsvc_form(model, request):
errors = list()
- fvar = GetReqVars(request, [ 'vmname', 'oldname', 'vmpath', 'recovery', 'domain', 'migration_type'])
+ fvar = GetReqVars(request, [ 'vmname', 'oldname', 'vmpath', 'recovery', 'domain', 'migration_type', 'max_restarts', 'restart_expire_time'])
vm_name = fvar['vmname']
if vm_name is None:
@@ -1087,6 +1114,32 @@
recovery = fvar['recovery']
if recovery is not None and recovery != 'restart' and recovery != 'relocate' and recovery != 'disable':
errors.append('You entered an invalid recovery option "%s" for VM service "%s". Valid options are "restart" "relocate" and "disable"' % (recovery, vm_name))
+ if recovery == 'restart':
+ max_restarts = None
+ if fvar['max_restarts']:
+ try:
+ max_restarts = int(fvar['max_restarts'])
+ if max_restarts < 0:
+ raise ValueError, 'must be greater than 0'
+ except Exception, e:
+ errors.append('Maximum restarts must be a number greater than or equal to 0')
+ max_restarts = None
+ restart_expire_time = None
+ if fvar['restart_expire_time']:
+ try:
+ restart_expire_time = int(fvar['restart_expire_time'])
+ if restart_expire_time < 0:
+ raise ValueError, 'must be greater than 0'
+ except Exception, e:
+ errors.append('Restart expire time must be a number greater than or equal to 0')
+ restart_expire_time = None
+
+ service_name = fvar['svc_name']
+ if service_name is None:
+ if LUCI_DEBUG_MODE is True:
+ luci_log.debug_verbose('vSA5: no service name')
+ errors.append('No service name was given')
+
migration_type = fvar['migration_type']
if migration_type is not None and migration_type != 'live' and migration_type != 'pause':
--- conga/luci/site/luci/Extensions/LuciZopeClusterPortal.py 2008/01/02 21:00:31 1.3
+++ conga/luci/site/luci/Extensions/LuciZopeClusterPortal.py 2008/07/29 19:47:03 1.4
@@ -251,10 +251,10 @@
if model.getIsVirtualized() is True:
vmadd = {}
- vmadd['Title'] = 'Add a Virtual Service'
+ vmadd['Title'] = 'Add a Virtual Machine Service'
vmadd['cfg_type'] = 'vmadd'
vmadd['absolute_url'] = '%s?pagetype=%s&clustername=%s' % (url, VM_ADD, cluname)
- vmadd['Description'] = 'Add a Virtual Service to this cluster'
+ vmadd['Description'] = 'Add a Virtual Machine Service to this cluster'
if pagetype == VM_ADD:
vmadd['currentItem'] = True
else:
@@ -305,7 +305,7 @@
svc['Title'] = name
svc['cfg_type'] = 'vm'
svc['absolute_url'] = '%s?pagetype=%s&servicename=%s&clustername=%s' % (url, VM_CONFIG, name, cluname)
- svc['Description'] = 'Configure this Virtual Service'
+ svc['Description'] = 'Configure this Virtual Machine Service'
if pagetype == VM_CONFIG:
try:
xname = request['servicename']
--- conga/luci/site/luci/Extensions/StorageReport.py 2008/04/23 17:33:37 1.30
+++ conga/luci/site/luci/Extensions/StorageReport.py 2008/07/29 19:47:03 1.31
@@ -1621,9 +1621,10 @@
mutable = var.getAttribute('mutable') == 'true'
var_type = var.getAttribute('type')
value = var.getAttribute('value')
+ def_value = value
d_units = ''
- if name in ('size', 'extent_size', 'block_size', 'size_free', 'partition_begin' ):
+ if name in ('size', 'extent_size', 'block_size', 'journal_size', 'size_free', 'partition_begin' ):
d_units = 'bytes'
if 'percent' in name:
d_units = '%'
@@ -1685,7 +1686,7 @@
d_value = str(value)
hidden = False
- if var_type == 'hidden' or name in ( 'partition_begin', 'snapshot' ):
+ if var_type == 'hidden' or name in ( 'partition_begin', 'snapshot' ) or name[0:11] == '__snap_size':
hidden = True
if name == 'removable':
@@ -1697,6 +1698,7 @@
'name': name,
'pretty_name': get_pretty_prop_name(name),
'type': d_type,
+ 'default_val': def_value,
'value': d_value,
'units': d_units,
'validation': validation_data,
--- conga/luci/site/luci/Extensions/cluster_adapters.py 2008/04/23 17:33:37 1.283
+++ conga/luci/site/luci/Extensions/cluster_adapters.py 2008/07/29 19:47:03 1.284
@@ -545,7 +545,9 @@
next_node_id = 1
try:
- for x in system_list:
+ skeys = system_list.keys()
+ skeys.sort()
+ for x in skeys:
i = system_list[x]
try:
@@ -1167,7 +1169,6 @@
msg_list.append('Fix the error and try again:\n')
else:
msg_list.append('PASSED\n')
- model.setModified(True)
msg_list.append('DONE\n')
msg_list.append('Propagating the new cluster.conf')
--- conga/luci/site/luci/Extensions/conga_constants.py 2008/03/05 23:08:58 1.50
+++ conga/luci/site/luci/Extensions/conga_constants.py 2008/07/29 19:47:04 1.51
@@ -155,6 +155,6 @@
# Debugging parameters. Set LUCI_DEBUG_MODE to True and LUCI_DEBUG_VERBOSITY
# to >= 2 to get full debugging output in syslog (LOG_DAEMON/LOG_DEBUG).
-LUCI_DEBUG_MODE = True
-LUCI_DEBUG_NET = True
-LUCI_DEBUG_VERBOSITY = 5
+LUCI_DEBUG_MODE = False
+LUCI_DEBUG_NET = False
+LUCI_DEBUG_VERBOSITY = 0
--- conga/luci/storage/form-macros 2008/01/02 20:52:23 1.31
+++ conga/luci/storage/form-macros 2008/07/29 19:47:04 1.32
@@ -87,6 +87,7 @@
</select>
</td>
</tr>
+ <tal:comment tal:replace="nothing">
<tr>
<td>
Display Devices by
@@ -99,6 +100,7 @@
</select>
</td>
</tr>
+ </tal:comment>
</table>
</form>
</fieldset>
@@ -865,21 +867,28 @@
<tal:block tal:condition="python:prop_type == 'select'">
<select tal:define="prop_options prop/value" tal:attributes="name p">
- <tal:block
- tal:condition="python: prop_units != 'bytes'"
- tal:repeat="prop_opt prop_options">
- <option tal:attributes="value prop_opt" />
- <span tal:replace="prop_opt" />
+ <tal:block tal:condition="python: prop_units != 'bytes'">
+ <tal:block tal:repeat="prop_opt prop_options">
+ <option tal:attributes="value prop_opt" />
+ <span tal:replace="prop_opt" />
+ </tal:block>
</tal:block>
- <tal:block
- tal:condition="python: prop_units == 'bytes'"
- tal:repeat="prop_opt prop_options">
- <option tal:attributes="value prop_opt" />
- <span
+
+ <tal:block tal:condition="python: prop_units == 'bytes'">
+ <tal:block
tal:define="
- dummy python: here.bytes_to_value_units(prop_opt);
- value python: str(dummy[0]) + ' ' + str(dummy[1])"
- tal:replace="value" />
+ dummy2 python:map(lambda x: int(x), prop_options);
+ dummy3 python:dummy2.sort()"
+ tal:repeat="prop_opt dummy2">
+ <option tal:attributes="
+ value prop_opt;
+ selected python:prop.get('default_val') == str(prop_opt) and 'selected' or ''" />
+ <span
+ tal:define="
+ dummy python: here.bytes_to_value_units(prop_opt);
+ value python: str(dummy[0]) + ' ' + str(dummy[1])"
+ tal:replace="value" />
+ </tal:block>
</tal:block>
</select>
</tal:block>
--- conga/ricci/modules/cluster/clumon/REDHAT-CLUSTER-MIB 2007/09/11 02:45:27 1.2
+++ conga/ricci/modules/cluster/clumon/REDHAT-CLUSTER-MIB 2008/07/29 19:47:05 1.3
@@ -13,7 +13,7 @@
1801 Varsity Drive
Raleigh, North Carolina 27606
USA
-
+
email: customerservice at redhat.com
"
DESCRIPTION "Red Hat Cluster Suite MIB
@@ -28,7 +28,7 @@
rhcMIBInfo OBJECT IDENTIFIER ::= { RedHatCluster 1 }
rhcCluster OBJECT IDENTIFIER ::= { RedHatCluster 2 }
rhcTables OBJECT IDENTIFIER ::= { RedHatCluster 3 }
-
+
@@ -86,7 +86,7 @@
MAX-ACCESS read-only
STATUS current
DESCRIPTION
- "Minimum number of votes required for quorum.
+ "Minimum number of votes required for quorum.
If cluster is not quorate, all services are stopped."
::= { rhcCluster 4 }
@@ -234,7 +234,7 @@
::= { rhcTables 1 }
rhcNodeEntry OBJECT-TYPE
- SYNTAX RchNodeEntry
+ SYNTAX RhcNodeEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
@@ -311,7 +311,7 @@
::= { rhcTables 2 }
rhcServiceEntry OBJECT-TYPE
- SYNTAX RchServiceEntry
+ SYNTAX RhcServiceEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
--- conga/ricci/modules/rpm/PackageHandler.cpp 2008/06/06 16:41:53 1.24
+++ conga/ricci/modules/rpm/PackageHandler.cpp 2008/07/29 19:47:05 1.25
@@ -511,9 +511,12 @@
if (kernel.find("xen") == kernel.npos) {
set.packages.push_back("kmod-gfs");
set.packages.push_back("kmod-gfs2");
+ set.packages.push_back("cmirror");
+ set.packages.push_back("kmod-cmirror");
} else {
set.packages.push_back("kmod-gfs-xen");
set.packages.push_back("kmod-gfs2-xen");
+ set.packages.push_back("kmod-cmirror-xen");
}
}
}
--- conga/ricci/modules/service/ServiceManager.cpp 2008/06/06 16:41:54 1.20
+++ conga/ricci/modules/service/ServiceManager.cpp 2008/07/29 19:47:06 1.21
@@ -521,11 +521,12 @@
servs.push_back("gfs");
servs.push_back("scsi_reserve");
} else if (RHEL5 || FC6) {
- descr = "Shared Storage: clvmd, gfs, gfs2";
+ descr = "Shared Storage: clvmd, cmirror, gfs, gfs2";
servs.push_back("clvmd");
servs.push_back("gfs");
servs.push_back("gfs2");
servs.push_back("scsi_reserve");
+ servs.push_back("cmirror");
}
s = ServiceSet(name, descr);
if (populate_set(s, servs))
--- conga/ricci/modules/storage/LVM.cpp 2007/09/11 02:45:28 1.13
+++ conga/ricci/modules/storage/LVM.cpp 2008/07/29 19:47:06 1.14
@@ -252,7 +252,7 @@
String attrs = words[LVS_ATTR_IDX];
props.set(Variable("attrs", attrs));
- props.set(Variable("mirrored", attrs[0] == 'm'));
+ props.set(Variable("mirrored", attrs[0] == 'm' || attrs[0] == 'M'));
// clustered
String vg_attrs = words[LVS_VG_ATTR_IDX];
@@ -602,17 +602,37 @@
void
LVM::lvremove(const String& path)
{
- vector<String> args;
- args.push_back("lvchange");
- args.push_back("-an");
- args.push_back(path);
-
- String out, err;
- int status;
- if (utils::execute(LVM_BIN_PATH, args, out, err, status, false))
- throw command_not_found_error_msg(LVM_BIN_PATH);
- if (status != 0)
- throw String("Unable to deactivate LV (might be in use by other cluster nodes)");
+ vector<String> args;
+ args.push_back("lvchange");
+ args.push_back("-an");
+ args.push_back(path);
+
+ String out, err;
+ int status;
+
+ if (utils::execute(LVM_BIN_PATH, args, out, err, status, false))
+ throw command_not_found_error_msg(LVM_BIN_PATH);
+
+ if (status != 0) {
+ bool ignore_err = false;
+
+ try {
+ Props props;
+ std::list<counting_auto_ptr<BD> > sources;
+ std::list<counting_auto_ptr<BD> > targets;
+ probe_vg(path, props, sources, targets);
+ if (props.get("snapshot").get_bool() ||
+ props.get("mirror").get_bool())
+ {
+ ignore_err = true;
+ }
+ } catch (...) {
+ ignore_err = false;
+ }
+
+ if (!ignore_err)
+ throw String("Unable to deactivate LV (might be in use by other cluster nodes)");
+ }
try {
args.clear();
--- conga/ricci/modules/virt/Makefile 2008/07/10 20:25:58 1.1
+++ conga/ricci/modules/virt/Makefile 2008/07/29 19:47:06 1.2
@@ -14,7 +14,7 @@
include ${top_srcdir}/make/defines.mk
-TARGET = modvirt
+TARGET = ricci-modvirt
OBJECTS = main.o \
VirtModule.o \
@@ -22,8 +22,11 @@
PARANOID=0
INCLUDE += -I${top_srcdir}/common/
-CXXFLAGS += -DPARANOIA=$(PARANOID)
-LDFLAGS += -lvirt
+CXXFLAGS += -DPARANOIA=$(PARANOID) -DVIRT_SUPPORT=$(VIRT_SUPPORT)
+
+ifeq ($(VIRT_SUPPORT), 1)
+ LDFLAGS += -lvirt
+endif
ifeq ($(PARANOID), 1)
LDFLAGS += ${top_srcdir}/common/paranoid/*.o
@@ -39,9 +42,9 @@
$(INSTALL_DIR) ${libexecdir}
$(INSTALL_BIN) ${TARGET} ${libexecdir}
$(INSTALL_DIR) ${sysconfdir}/oddjobd.conf.d
- $(INSTALL_FILE) d-bus/modvirt.oddjob.conf ${sysconfdir}/oddjobd.conf.d
+ $(INSTALL_FILE) d-bus/ricci-modvirt.oddjob.conf ${sysconfdir}/oddjobd.conf.d
$(INSTALL_DIR) ${sysconfdir}/dbus-1/system.d
- $(INSTALL_FILE) d-bus/modvirt.systembus.conf ${sysconfdir}/dbus-1/system.d
+ $(INSTALL_FILE) d-bus/ricci-modvirt.systembus.conf ${sysconfdir}/dbus-1/system.d
uninstall:
--- conga/ricci/modules/virt/Virt.cpp 2008/07/10 20:25:58 1.1
+++ conga/ricci/modules/virt/Virt.cpp 2008/07/29 19:47:06 1.2
@@ -23,7 +23,9 @@
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
+#if VIRT_SUPPORT == 1
#include <libvirt/libvirt.h>
+#endif
#include "sys_util.h"
#include "base64.h"
@@ -53,6 +55,8 @@
return false;
}
+#if VIRT_SUPPORT == 1
+
map<String, String> Virt::get_vm_list(const String &hvURI) {
std::map<String, String> vm_list;
int i;
@@ -130,3 +134,13 @@
virConnectClose(con);
return vm_list;
}
+
+#else
+
+map<String, String> Virt::get_vm_list(const String &hvURI) {
+ std::map<String, String> vm_list;
+ throw String("Unsupported on this architecture.");
+ return vm_list;
+}
+
+#endif
--- conga/ricci/ricci/DBusController.cpp 2008/01/02 20:47:38 1.18
+++ conga/ricci/ricci/DBusController.cpp 2008/07/29 19:47:06 1.19
@@ -41,12 +41,12 @@
DBusController::DBusController()
{
// TODO: dynamically determine,
- // currently, rpm requires storage and cluster modules
_mod_map["storage"] = "modstorage_rw";
_mod_map["cluster"] = "modcluster_rw";
_mod_map["rpm"] = "modrpm_rw";
_mod_map["log"] = "modlog_rw";
_mod_map["service"] = "modservice_rw";
+ _mod_map["virt"] = "modvirt_rw";
_mod_map["reboot"] = "reboot";
MutexLocker lock(_dbus_mutex);
--- conga/ricci/ricci/d-bus/ricci.oddjob.conf 2006/06/15 03:08:37 1.1
+++ conga/ricci/ricci/d-bus/ricci.oddjob.conf 2008/07/29 19:47:06 1.2
@@ -18,6 +18,9 @@
<method name="modservice_rw">
<allow user="ricci"/>
</method>
+ <method name="modvirt_rw">
+ <allow user="ricci"/>
+ </method>
<method name="reboot">
<helper exec="/sbin/reboot"
arguments="0"
--- conga/ricci/test_suite/cluster/vm_list.xml 2008/03/14 19:58:12 1.1
+++ conga/ricci/test_suite/cluster/vm_list.xml 2008/07/29 19:47:07 1.2
@@ -2,7 +2,7 @@
<ricci version="1.0" function="process_batch" async="false">
<batch>
-<module name="cluster">
+<module name="virt">
<request sequence="1254" API_version="1.0">
<function_call name="list_vm" />
</request>
next reply other threads:[~2008-07-29 19:47 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-07-29 19:47 rmccabe [this message]
-- strict thread matches above, loose matches on Subject: below --
2008-07-28 17:49 [Cluster-devel] conga ./clustermon.spec.in.in ./conga.spec.in. rmccabe
2008-05-12 15:13 rmccabe
2008-04-18 3:31 rmccabe
2008-04-11 6:54 rmccabe
2008-04-11 6:48 rmccabe
2008-04-07 20:11 rmccabe
2008-02-12 17:40 rmccabe
2008-01-29 22:02 rmccabe
2007-08-20 16:23 rmccabe
2007-08-13 19:06 rmccabe
2007-08-09 22:02 rmccabe
2007-08-08 21:24 rmccabe
2007-06-27 7:43 rmccabe
2007-05-01 15:57 rmccabe
2007-04-11 20:15 rmccabe
2007-04-11 19:23 rmccabe
2007-03-20 20:52 kupcevic
2007-02-07 1:36 kupcevic
2007-02-05 22:01 kupcevic
2007-02-05 20:08 rmccabe
2007-02-05 12:12 kupcevic
2007-01-23 22:34 kupcevic
2007-01-17 16:36 kupcevic
2007-01-17 14:57 kupcevic
2007-01-17 14:32 kupcevic
2006-12-13 19:21 kupcevic
2006-12-12 13:53 kupcevic
2006-11-17 20:46 kupcevic
2006-11-17 0:59 kupcevic
2006-11-16 19:35 kupcevic
2006-11-02 0:46 rmccabe
2006-11-01 23:11 kupcevic
2006-11-01 20:43 rmccabe
2006-10-31 20:34 kupcevic
2006-10-25 18:47 rmccabe
2006-10-25 16:35 kupcevic
2006-10-16 21:01 kupcevic
2006-10-16 15:56 kupcevic
2006-10-04 16:32 kupcevic
2006-09-26 5:21 kupcevic
2006-08-22 23:01 kupcevic
2006-08-22 20:12 kupcevic
2006-08-16 6:34 kupcevic
2006-08-15 4:15 kupcevic
2006-08-09 21:13 kupcevic
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080729194715.12808.qmail@sourceware.org \
--to=rmccabe@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.