[luci] Invoke paster by executing /usr/bin/python -Es /usr/bin/paster to stop python from searching the cur
by Ryan McCabe
commit 73f6bf3334e3c95ee4599ebebc4e4404aa04b780
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Jun 27 16:11:25 2011 -0400
Invoke paster by executing /usr/bin/python -Es /usr/bin/paster to stop python from searching the current user's directory.
Fixes bz632536
input_files/initscript/initscript.in | 25 +++++++++++--------------
setup.cfg | 2 +-
2 files changed, 12 insertions(+), 15 deletions(-)
---
diff --git a/input_files/initscript/initscript.in b/input_files/initscript/initscript.in
index 66d72e1..1a6d871 100755
--- a/input_files/initscript/initscript.in
+++ b/input_files/initscript/initscript.in
@@ -77,9 +77,6 @@ entry_check() {
# Must be either root or the @USERNAME@ user to run this
echo "Insufficient permissions" >&2
return 4
- elif [ ! -x "$exec" ]; then
- echo "Missing program or component installed: paster (paste.script)" >&2
- return 5
fi
}
@@ -104,7 +101,7 @@ certconfig_complete() {
# identification within the certificate, no information about
# these IPs added (for confidentality reasons)
for IP_ADDR in $IP_ADDRS; do
- DOM_NAME=$(python -c "from socket import getfqdn; print(getfqdn('$IP_ADDR'))" 2>/dev/null)
+ DOM_NAME=$(/usr/bin/python -Es -c "from socket import getfqdn; print(getfqdn('$IP_ADDR'))" 2>/dev/null)
if [ -n "$DOM_NAME" -a "$DOM_NAME" != "$IP_ADDR" ]; then
echo "DNS.$CNT_DOM_NAME = $DOM_NAME" >>"$CERT_CONFIG"
echo -e "\tDNS: $DOM_NAME" >&2
@@ -120,7 +117,7 @@ certconfig_complete() {
echo "IP.$CNT_IP_ADDR = $IP_ADDR" >>"$CERT_CONFIG"
echo -e "\tIP: $IP_ADDR" >&2
let CNT_IP_ADDR++
- DOM_NAME=$(python -c "from socket import getfqdn; print(getfqdn('$IP_ADDR'))" 2>/dev/null)
+ DOM_NAME=$(/usr/bin/python -Es -c "from socket import getfqdn; print(getfqdn('$IP_ADDR'))" 2>/dev/null)
if [ -n "$DOM_NAME" -a "$DOM_NAME" != "$IP_ADDR" ]; then
echo "DNS.$CNT_DOM_NAME = $DOM_NAME" >>"$CERT_CONFIG"
echo -e "\tDNS: $DOM_NAME" >&2
@@ -140,7 +137,7 @@ certconfig_complete() {
prepare_config() {
# Touching $config first and then using ``.. make-config .. --overwrite''
# does not work now (see http://trac.pythonpaste.org/pythonpaste/ticket/450)
- "$exec" make-config $PKG_NAME "$config" --no-default-sysconfig --no-install &>/dev/null
+ $exec make-config $PKG_NAME "$config" --no-default-sysconfig --no-install &>/dev/null
if [ $? -ne 0 ]; then
rm -f -- "$config" &>/dev/null
echo "Unable to create the $PKG_NAME base configuration file (\`$config')." >&2
@@ -164,7 +161,7 @@ prepare_db() {
echo "Unable to change ownership/attributes of the $PKG_NAME database file (\`$DB_FILE')." >&2
return 1
fi
- "$exec" setup-app "$config" --no-default-sysconfig &>/dev/null
+ $exec setup-app "$config" --no-default-sysconfig &>/dev/null
if [ $? -ne 0 ]; then
rm -f -- "$DB_FILE" &>/dev/null
echo "Unable to create the $PKG_NAME database file (\`$DB_FILE')." >&2
@@ -277,9 +274,9 @@ start_server() {
cd /etc/init.d || return 1
./saslauthd start || return 1
- "$exec" serve --daemon --user "$DAEMON_USER" --group "$DAEMON_GROUP" \
- --log-file="$LOG_FILE" --pid-file="$PID_FILE" \
- --server-name=init --app-name=init "$config" @RELOAD@ >/dev/null
+ $exec serve --daemon --user "$DAEMON_USER" --group "$DAEMON_GROUP" \
+ --log-file="$LOG_FILE" --pid-file="$PID_FILE" \
+ --server-name=init --app-name=init "$config" @RELOAD@ >/dev/null
}
start() {
@@ -287,7 +284,7 @@ start() {
CUSTOM_HOST=$(echo "$INIT_CONFIG" | sed 's/\$/\n/g' | sed '/^[ \t]*host[ \t]*=/!d; s/[^=]*=[ \t]*\([^$]\+\)$/\1/')
[ -n "$CUSTOM_HOST" ] && HOST="$CUSTOM_HOST"
- [ "$HOST" == "0.0.0.0" ] && HOST=$(python -c "from socket import getfqdn; print(getfqdn())" 2>/dev/null)
+ [ "$HOST" == "0.0.0.0" ] && HOST=$(/usr/bin/python -Es -c "from socket import getfqdn; print(getfqdn())" 2>/dev/null)
[ -z "$HOST" ] && HOST="127.0.0.1"
CUSTOM_PORT=$(echo "$INIT_CONFIG" | sed 's/\$/\n/g' | sed '/^[ \t]*port[ \t]*=/!d; s/[^=]*=[ \t]*\([^$]\+\)$/\1/')
@@ -319,8 +316,8 @@ start() {
stop() {
step=$"Stop $prog..."
- # If PID file does not exists, paster returns 1 otherwise 0
- "$exec" serve --stop-daemon --pid-file="$PID_FILE" >/dev/null
+ # If PID file does not exist, paster returns 1 otherwise 0
+ $exec serve --stop-daemon --pid-file="$PID_FILE" >/dev/null
ret=$?
if [ $ret -eq 0 ]; then
if [ "$KEEP_RUNTIME_DATA" -eq "0" ]; then
@@ -340,7 +337,7 @@ restart() {
status() {
# If PID file exists and contains valid PID, paster returns 0 otherwise 1
- out=$("$exec" serve --status --pid-file="$PID_FILE" "$config" 2>&1)
+ out=$($exec serve --status --pid-file="$PID_FILE" "$config" 2>&1)
ret=$?
echo "$out" | tail -1
if [ $ret -ne 0 ]; then
diff --git a/setup.cfg b/setup.cfg
index 4ff7bb6..a2f403b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -21,7 +21,7 @@ logfile = /var/log/luci/luci.log
# System files (initscript and configuration files)
initscript = /etc/rc.d/init.d/luci
sysconfig = /etc/sysconfig/luci
-launcher = /usr/bin/paster
+launcher = /usr/bin/python -Es /usr/bin/paster
logrotateconfig = /etc/logrotate.d/luci
pamconfig = /etc/pam.d/luci
sasl2config = /etc/sasl2/luci.conf
12 years, 11 months
[luci] Title case and whitespace cleanups
by Ryan McCabe
commit 9ac4eae1ae2ee575ce2d7238ada5e4327db132db
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Jun 27 15:20:47 2011 -0400
Title case and whitespace cleanups
luci/public/js/add_nodes.js | 4 +-
luci/public/js/cluster_list.js | 2 +-
luci/public/js/failover_form.js | 2 +-
luci/public/js/fence.js | 3 +-
luci/public/js/homebase.js | 24 +-------
luci/public/js/resource.js | 2 +-
luci/public/js/service.js | 8 +-
luci/templates/about.html | 52 +++------------
luci/templates/footer.html | 13 ++--
luci/templates/header.html | 16 ++--
luci/templates/homebase.html | 136 +++++++++++++++++++--------------------
luci/templates/login.html | 21 +++---
luci/templates/master.html | 88 ++++++++++++-------------
luci/templates/submenu.html | 22 +++---
luci/templates/title.html | 4 +-
15 files changed, 168 insertions(+), 229 deletions(-)
---
diff --git a/luci/public/js/add_nodes.js b/luci/public/js/add_nodes.js
index 18d3d42..526d6f8 100644
--- a/luci/public/js/add_nodes.js
+++ b/luci/public/js/add_nodes.js
@@ -1,10 +1,10 @@
$(function() {
$('#add_nodes_dialog').dialog({
modal: true,
- title: 'Add Nodes To Cluster',
+ title: 'Add Nodes to Cluster',
width: '720px',
autoOpen: false,
draggable: false,
- resizable: false,
+ resizable: true,
});
})
diff --git a/luci/public/js/cluster_list.js b/luci/public/js/cluster_list.js
index 05f9474..ff3ee04 100644
--- a/luci/public/js/cluster_list.js
+++ b/luci/public/js/cluster_list.js
@@ -16,6 +16,6 @@ $(function() {
width: '720px',
autoOpen: false,
draggable: false,
- resizable: false,
+ resizable: true,
});
})
diff --git a/luci/public/js/failover_form.js b/luci/public/js/failover_form.js
index e6e3272..71f8b93 100644
--- a/luci/public/js/failover_form.js
+++ b/luci/public/js/failover_form.js
@@ -1,7 +1,7 @@
$(function() {
$('#create_fdom_dialog').dialog({
modal: true,
- title: 'Add Failover Domain To Cluster',
+ title: 'Add Failover Domain to Cluster',
width: '520px',
autoOpen: false,
draggable: false,
diff --git a/luci/public/js/fence.js b/luci/public/js/fence.js
index 2a3c9c4..d654aea 100644
--- a/luci/public/js/fence.js
+++ b/luci/public/js/fence.js
@@ -10,13 +10,12 @@ $(function() {
$('#create_fencemethod_dialog').dialog({
modal: true,
- title: 'Add Fence Method To Node',
+ title: 'Add Fence Method to Node',
width: '520px',
autoOpen: false,
draggable: false,
resizable: false,
});
-
})
function swap_fence_form(fence_form_id, container_id) {
diff --git a/luci/public/js/homebase.js b/luci/public/js/homebase.js
index 3414c50..fb8474f 100644
--- a/luci/public/js/homebase.js
+++ b/luci/public/js/homebase.js
@@ -1,32 +1,10 @@
$(function() {
$('#luci_homebase_add_existing').dialog({
modal: true,
- title: 'Add an Existing Cluster',
+ title: 'Add Existing Cluster',
width: '720px',
autoOpen: false,
draggable: false,
resizable: false,
});
})
-
-$(function() {
- $('#luci_homebase_manage').dialog({
- modal: true,
- title: 'Manage Systems and Clusters',
- width: '520px',
- autoOpen: false,
- draggable: false,
- resizable: false,
- });
-})
-
-$(function() {
- $('#luci_homebase_user').dialog({
- modal: true,
- title: 'User Management',
- width: '520px',
- autoOpen: false,
- draggable: false,
- resizable: false,
- });
-})
diff --git a/luci/public/js/resource.js b/luci/public/js/resource.js
index f022654..22fded5 100644
--- a/luci/public/js/resource.js
+++ b/luci/public/js/resource.js
@@ -1,7 +1,7 @@
$(function() {
$('#add_resource_dialog').dialog({
modal: true,
- title: 'Add Resource To Cluster',
+ title: 'Add Resource to Cluster',
width: '520px',
autoOpen: false,
draggable: false,
diff --git a/luci/public/js/service.js b/luci/public/js/service.js
index e2a8428..7014120 100644
--- a/luci/public/js/service.js
+++ b/luci/public/js/service.js
@@ -1,18 +1,18 @@
$(function() {
$('#add_service_dialog').dialog({
modal: true,
- title: 'Add Service To Cluster',
- width: '520px',
+ title: 'Add Service Group to Cluster',
+ width: '720px',
autoOpen: false,
draggable: false,
- resizable: false,
+ resizable: true,
});
})
$(function() {
$('#insert_resource_dialog').dialog({
modal: true,
- title: 'Add Resource To Service',
+ title: 'Add Resource to Service',
width: '520px',
autoOpen: false,
draggable: false,
diff --git a/luci/templates/about.html b/luci/templates/about.html
index 2f5a908..98a1132 100644
--- a/luci/templates/about.html
+++ b/luci/templates/about.html
@@ -1,51 +1,21 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude">
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
-<xi:include href="master.html" />
+<xi:include href="master.html"/>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
- <title>Conga User Manual</title>
+ <title>About Luci</title>
</head>
- <body>
-
+<body>
<div class="sectionblock about">
- <h2>Conga Architecture</h2>
-
- <p>Conga is an agent/server architecture for remote administration of
- systems. The agent component is called "ricci", and the server is called
- "luci". One luci server can communicate with many multiple ricci agents
- installed on systems. When a system is added to a luci server to be
- administered, authentication is done once. No authentication is necessary from
- then on. Through the UI provided by luci, users can configure and
- administer cluster behavior on remote systems. Communication between luci and ricci is done via XML over SSL.</p>
-
- <h2>Luci Description</h2>
-
- <p>As stated above, systems to be administered are "added" to a luci server (in
- the documentation that follows, the term "registered" is also used to mean
- that a system has been added to a luci server to be administered remotely). This
- is done by storing the hostname (FQDN) or IP address of the system in the luci
- database. When a luci server is first installed, the database is empty. It is
- possible, however, to import part or all of a systems database from an
- existing luci server when deploying a new luci server. This capability
- provides a means for replication of a luci server instance, as well as an
- easier upgrade and testing path.</p>
-
- <h2>Legal</h2>
- <a href="http://www.sourceware.org/cluster/conga">luci</a>
- is Copyright <acronym title="Copyright">©</acronym> 2006–2010
- <a href="http://www.redhat.com/">Red Hat, Inc.</a>
- <p>
- Distributed under the
- <a href="http://creativecommons.org/licenses/GPL/2.0/">GNU GPL v2 license</a>.
- </p>
- </div>
-
- </body>
+ <h2>Legal</h2>
+ <a href="http://www.sourceware.org/cluster/conga">luci</a> is Copyright <acronym title="Copyright">©</acronym> 2006–2011 <a href="http://www.redhat.com/">Red Hat, Inc.</a>
+ <p>Distributed under the <a href="http://creativecommons.org/licenses/GPL/2.0/">GNU GPL v2 license</a>.</p>
+ </div>
+</body>
</html>
-
diff --git a/luci/templates/footer.html b/luci/templates/footer.html
index 7af102d..ff5fc46 100644
--- a/luci/templates/footer.html
+++ b/luci/templates/footer.html
@@ -1,15 +1,12 @@
<html xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- py:strip="">
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
<py:def function="footer">
<div id="footer">
<div class="foottext">
- Copyright <acronym title="Copyright">©</acronym> 2006–2010
- <a href="http://www.redhat.com/">Red Hat, Inc.</a>
- <p>
- Distributed under the
- <a href="http://creativecommons.org/licenses/GPL/2.0/">GNU GPL v2 license</a>.
- </p>
+ Copyright <acronym title="Copyright">©</acronym> 2006–2011
+ <a href="http://www.redhat.com/">Red Hat, Inc.</a>
+ <p>Distributed under the <a href="http://creativecommons.org/licenses/GPL/2.0/">GNU GPL v2 license</a>.</p>
</div>
<div class="clearingdiv"></div>
</div>
diff --git a/luci/templates/header.html b/luci/templates/header.html
index 55e3856..568d9fb 100644
--- a/luci/templates/header.html
+++ b/luci/templates/header.html
@@ -1,17 +1,17 @@
<html xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- py:strip="">
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
<py:def function="header">
<div id="header">
<h1><img src="/images/logo.png" alt="High Availability management logo"/></h1>
- <ul class="headermenu">
- <li><a href="${tg.url('/about')}" class="${('', 'active')[defined('page') and page==page=='about']}">About</a></li>
- <span py:if="tg.auth_stack_enabled" py:strip="True">
+ <ul class="headermenu">
+ <li><a href="${tg.url('/about')}" class="${('', 'active')[defined('page') and page==page=='about']}">About</a></li>
+ <span py:if="tg.auth_stack_enabled" py:strip="True">
<py:if test="request.identity">
- <li class="loginlogout"><a href="${tg.url('/prefs')}" class="${('', 'active')[defined('page') and page==page=='prefs']}">Preferences</a></li>
- <li id="login" class="loginlogout"><a href="${tg.url('/logout_handler')}">Logout</a></li>
+ <li class="loginlogout"><a href="${tg.url('/prefs')}" class="${('', 'active')[defined('page') and page==page=='prefs']}">Preferences</a></li>
+ <li id="login" class="loginlogout"><a href="${tg.url('/logout_handler')}">Logout</a></li>
</py:if>
- <li py:if="not request.identity" id="login" class="loginlogout"><a href="${tg.url('/login')}">Login</a></li>
+ <li py:if="not request.identity" id="login" class="loginlogout"><a href="${tg.url('/login')}">Login</a></li>
</span>
</ul>
</div>
diff --git a/luci/templates/homebase.html b/luci/templates/homebase.html
index d4a2d29..bb7b3f8 100644
--- a/luci/templates/homebase.html
+++ b/luci/templates/homebase.html
@@ -1,14 +1,13 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude">
-
-<xi:include href="master.html" />
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+<xi:include href="master.html"/>
<head>
-<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
-<title>Luci Homebase</title>
+ <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
+ <title>Luci Homebase</title>
</head>
<?python
@@ -16,67 +15,66 @@
?>
<body py:with="clusters = db_helpers.get_cluster_list_full()">
- <div class="mainpage">
- <div py:if="homebasepage == 'homebasepage'">
- <!-- <h2>Notifications</h2> -->
- <h2><a href="${tg.url('/cluster')}" class="${('', 'active')[defined('page') and page=='clusters']}">Cluster Summary</a></h2>
- <div id="overview">
- <table id="clusters_tlist" class="maintable">
- <thead>
- <tr>
- <th class="main_id">Name</th>
- <th class="cluster_tlist_status">Status</th>
- <th class="cluster_tlist_votes">Nodes Joined</th>
- </tr>
- </thead>
- <tbody>
- <tr py:for="i, (entity_name, cluster_data) in enumerate(clusters.iteritems())"
- py:attrs="not i%2 and {'class': 'even'} or None">
- <py:if test="hasattr(cluster_data['status'],'quorate')">
- <!--! Branch according to the status of the cluster. -->
- <py:choose test="cluster_data['status'].quorate">
- <!--! 1) Cluster is OK. -->
- <py:when test="'true'">
- <td class="main_id">
- <a href="${tg.url(base_url + '/' + entity_name) + '/'}">
- <span class="entity_ok">${entity_name}</span>
- </a>
- </td>
- <td class="cluster_tlist_status">Quorate</td>
- </py:when>
- <!--! 2) Cluster is not OK. -->
- <py:when test="'false'">
- <td class="main_id">
- <a href="${tg.url(base_url + '/' + entity_name)}">
- <span class="entity_fail">${entity_name}</span>
- </a>
- </td>
- <td class="cluster_tlist_status">Not Quorate</td>
- </py:when>
- <!--! 3) Status of the cluster is unknown. -->
- <py:when test="">
- <td class="main_id">
- <a href="${tg.url(base_url + '/' + entity_name)}">
- <span class="entity_unknown">${entity_name}</span>
- </a>
- </td>
- <td class="cluster_tlist_status">Status unknown</td>
- </py:when>
- </py:choose>
- <py:choose test="cluster_data and cluster_data.get('model') and cluster_data.get('status') and True">
- <py:when test="True">
- <td class="cluster_tlist_votes">${cluster_data['status'].nodesClustered} of ${len(cluster_data['model'].getNodes())}</td>
- </py:when>
- <py:otherwise>
- <td class="cluster_tlist_votes">-</td>
- </py:otherwise>
- </py:choose>
- </py:if>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- </div>
+ <div class="mainpage">
+ <div py:if="homebasepage == 'homebasepage'">
+ <h2><a href="${tg.url('/cluster')}" class="${('', 'active')[defined('page') and page=='clusters']}">Cluster Summary</a></h2>
+ <div id="overview">
+ <table id="clusters_tlist" class="maintable">
+ <thead>
+ <tr>
+ <th class="main_id">Name</th>
+ <th class="cluster_tlist_status">Status</th>
+ <th class="cluster_tlist_votes">Nodes Joined</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr py:for="i, (entity_name, cluster_data) in enumerate(clusters.iteritems())"
+ py:attrs="not i%2 and {'class': 'even'} or None">
+ <py:if test="hasattr(cluster_data['status'],'quorate')">
+ <!--! Branch according to the status of the cluster. -->
+ <py:choose test="cluster_data['status'].quorate">
+ <!--! 1) Cluster is OK. -->
+ <py:when test="'true'">
+ <td class="main_id">
+ <a href="${tg.url(base_url + '/' + entity_name) + '/'}">
+ <span class="entity_ok">${entity_name}</span>
+ </a>
+ </td>
+ <td class="cluster_tlist_status">Quorate</td>
+ </py:when>
+ <!--! 2) Cluster is not OK. -->
+ <py:when test="'false'">
+ <td class="main_id">
+ <a href="${tg.url(base_url + '/' + entity_name)}">
+ <span class="entity_fail">${entity_name}</span>
+ </a>
+ </td>
+ <td class="cluster_tlist_status">Not Quorate</td>
+ </py:when>
+ <!--! 3) Status of the cluster is unknown. -->
+ <py:when test="">
+ <td class="main_id">
+ <a href="${tg.url(base_url + '/' + entity_name)}">
+ <span class="entity_unknown">${entity_name}</span>
+ </a>
+ </td>
+ <td class="cluster_tlist_status">Status unknown</td>
+ </py:when>
+ </py:choose>
+ <py:choose test="cluster_data and cluster_data.get('model') and cluster_data.get('status') and True">
+ <py:when test="True">
+ <td class="cluster_tlist_votes">${cluster_data['status'].nodesClustered} of ${len(cluster_data['model'].getNodes())}</td>
+ </py:when>
+ <py:otherwise>
+ <td class="cluster_tlist_votes">-</td>
+ </py:otherwise>
+ </py:choose>
+ </py:if>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
</body>
</html>
diff --git a/luci/templates/login.html b/luci/templates/login.html
index 402111c..0aa6f5b 100644
--- a/luci/templates/login.html
+++ b/luci/templates/login.html
@@ -1,25 +1,24 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude">
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
-<xi:include href="master.html" />
+<xi:include href="master.html"/>
<head>
-<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
-<title>Login Form</title>
+ <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
+ <title>Login Form</title>
</head>
<body>
-<div id="loginform">
-<form action="${tg.url('/login_handler', came_from = came_from.encode('utf-8'), __logins = login_counter.encode('utf-8'))}" method="post" class="loginfields">
+ <div id="loginform">
+ <form action="${tg.url('/login_handler', came_from = came_from.encode('utf-8'), __logins = login_counter.encode('utf-8'))}" method="post" class="loginfields">
<h2><span>Login</span></h2>
<div class="row"><label for="login">Username</label><input type="text" id="login" name="login" class="text"></input></div>
<div class="row"><label for="password">Password</label><input type="password" id="password" name="password" class="text"></input></div>
<div class="row"><input type="submit" class="button formsubmit blue" id="submit" value="Login" /></div>
-</form>
-
-</div>
+ </form>
+ </div>
</body>
</html>
diff --git a/luci/templates/master.html b/luci/templates/master.html
index 527783a..0417409 100644
--- a/luci/templates/master.html
+++ b/luci/templates/master.html
@@ -1,48 +1,48 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- py:strip="">
- <xi:include href="header.html" />
- <xi:include href="footer.html" />
- <xi:include href="title.html" />
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
+ <xi:include href="header.html"/>
+ <xi:include href="footer.html"/>
+ <xi:include href="title.html"/>
<?python
- from luci.lib import db_helpers
- expertMode = request.cookies.get('expertMode') == '1'
+ from luci.lib import db_helpers
+ expertMode = request.cookies.get('expertMode') == '1'
?>
<head py:match="head" py:attrs="select('@*')">
- <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
- <title py:replace="''">Your title goes here</title>
- <meta py:replace="select('*')"/>
- <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/style.css')}" />
- <link rel="stylesheet" type="text/css" href="/css/jquery-ui-1.8.11.custom.css" />
- <link rel="stylesheet" type="text/css" href="/css/jquery.jnotify-alt.css"/>
+ <meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
+ <title py:replace="''">Your title goes here</title>
+ <meta py:replace="select('*')"/>
+ <link rel="stylesheet" type="text/css" media="screen" href="${tg.url('/css/style.css')}" />
+ <link rel="stylesheet" type="text/css" href="/css/jquery-ui-1.8.11.custom.css" />
+ <link rel="stylesheet" type="text/css" href="/css/jquery.jnotify-alt.css"/>
- <script type="text/javascript" src="/js/shared.js"></script>
- <script type="text/javascript" src="/js/jquery-1.5.2.min.js"></script>
- <script type="text/javascript" src="/js/jquery-ui-1.8.11.custom.min.js"></script>
- <script type="text/javascript" src="/js/jquery.blockUI.min.js"></script>
- <script type="text/javascript" src="/js/jquery.jnotify.min.js"></script>
- <script type="text/javascript" src="/js/homebase.js"></script>
- <script type="text/javascript" src="/js/busy.js"></script>
+ <script type="text/javascript" src="/js/shared.js"></script>
+ <script type="text/javascript" src="/js/jquery-1.5.2.min.js"></script>
+ <script type="text/javascript" src="/js/jquery-ui-1.8.11.custom.min.js"></script>
+ <script type="text/javascript" src="/js/jquery.blockUI.min.js"></script>
+ <script type="text/javascript" src="/js/jquery.jnotify.min.js"></script>
+ <script type="text/javascript" src="/js/homebase.js"></script>
+ <script type="text/javascript" src="/js/busy.js"></script>
</head>
<body py:match="body" py:attrs="select('@*')">
<div id="status_msg_area" style="display:none">
<div id="status_header" class="row">
- <img id="status_msg_img" src="/images/100wait.gif" height="50" width="50"/>
- <span id="status_header_text">Please wait...</span>
+ <img id="status_msg_img" src="/images/100wait.gif" height="50" width="50"/>
+ <span id="status_header_text">Please wait...</span>
</div>
<ul id="status_msg_details"/>
</div>
<py:if test="'cluster_name' in dir(tmpl_context)">
<script type="text/javascript">
- $(document).ready(function() {
- poll_cluster_busy('${tmpl_context.cluster_name}');
- });
+ $(document).ready(function() {
+ poll_cluster_busy('${tmpl_context.cluster_name}');
+ });
</script>
</py:if>
<div id="wrapper">
@@ -55,30 +55,28 @@
<li></li>
</ul>
</div>
-
<div id="content">
- <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
- <div py:if="flash" py:content="XML(flash)" class="message"/>
- </py:with>
- <py:if test="'flash2' in session">
- <div py:for="message in session['flash2']" class="message" id="${message.hash}">
- <div py:if="message.hideable" class="hide_btn">
- <a href="#" onclick="$('#${message.hash}').hide('blind',{},500,function(){});">Hide</a>
- </div>
- <div py:if="message.html" class="${message.css}" py:content="XML(message.message)"/>
- <div py:if="not message.html" class="${message.css}" py:content="message.message"/>
+ <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
+ <div py:if="flash" py:content="XML(flash)" class="message"/>
+ </py:with>
+ <py:if test="'flash2' in session">
+ <div py:for="message in session['flash2']" class="message" id="${message.hash}">
+ <div py:if="message.hideable" class="hide_btn">
+ <a href="#" onclick="$('#${message.hash}').hide('blind',{},500,function(){});">Hide</a>
</div>
- </py:if>
- <py:if test="'show_sidebar' in dir(tmpl_context) and tmpl_context.show_sidebar">
- <xi:include href="mainmenu.html" />
- </py:if>
- <py:if test="defined('page')">
- <div class="currentpage">
+ <div py:if="message.html" class="${message.css}" py:content="XML(message.message)"/>
+ <div py:if="not message.html" class="${message.css}" py:content="message.message"/>
</div>
</py:if>
+ <py:if test="'show_sidebar' in dir(tmpl_context) and tmpl_context.show_sidebar">
+ <xi:include href="mainmenu.html" />
+ </py:if>
+ <py:if test="defined('page')">
+ <div class="currentpage"></div>
+ </py:if>
<div py:replace="select('*|text()')"/>
<!-- End of content -->
- </div>
</div>
+ </div>
</body>
</html>
diff --git a/luci/templates/submenu.html b/luci/templates/submenu.html
index 5ca3c0f..b0893d5 100644
--- a/luci/templates/submenu.html
+++ b/luci/templates/submenu.html
@@ -1,15 +1,15 @@
<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- py:strip="">
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
<py:if test="'cluster_url' in dir(tmpl_context)">
- <ul class="submenu">
- <li><a href="${tg.url(tmpl_context.cluster_url + 'nodes')}" class="${('', 'active')[base_url.endswith('/nodes')]}">Nodes</a></li>
- <li><a href="${tg.url(tmpl_context.cluster_url +'fences')}" class="${('', 'active')[base_url.endswith('/fences')]}">Fence Devices</a></li>
- <li><a href="${tg.url(tmpl_context.cluster_url + 'failovers')}" class="${('', 'active')[base_url.endswith('/failovers')]}">Failover Domains</a></li>
- <li><a href="${tg.url(tmpl_context.cluster_url + 'resources')}" class="${('', 'active')[base_url.endswith('/resources')]}">Resources</a></li>
- <li><a href="${tg.url(tmpl_context.cluster_url + 'services')}" class="${('', 'active')[base_url.endswith('/services')]}">Service Groups</a></li>
- <li><a href="${tg.url(tmpl_context.cluster_url +'configure')}" class="${('', 'active')[base_url.endswith('/configure')]}">Configure</a></li>
- </ul>
+ <ul class="submenu">
+ <li><a href="${tg.url(tmpl_context.cluster_url + 'nodes')}" class="${('', 'active')[base_url.endswith('/nodes')]}">Nodes</a></li>
+ <li><a href="${tg.url(tmpl_context.cluster_url +'fences')}" class="${('', 'active')[base_url.endswith('/fences')]}">Fence Devices</a></li>
+ <li><a href="${tg.url(tmpl_context.cluster_url + 'failovers')}" class="${('', 'active')[base_url.endswith('/failovers')]}">Failover Domains</a></li>
+ <li><a href="${tg.url(tmpl_context.cluster_url + 'resources')}" class="${('', 'active')[base_url.endswith('/resources')]}">Resources</a></li>
+ <li><a href="${tg.url(tmpl_context.cluster_url + 'services')}" class="${('', 'active')[base_url.endswith('/services')]}">Service Groups</a></li>
+ <li><a href="${tg.url(tmpl_context.cluster_url +'configure')}" class="${('', 'active')[base_url.endswith('/configure')]}">Configure</a></li>
+ </ul>
</py:if>
</html>
diff --git a/luci/templates/title.html b/luci/templates/title.html
index a174516..dc7e895 100644
--- a/luci/templates/title.html
+++ b/luci/templates/title.html
@@ -1,6 +1,6 @@
<html xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- py:strip="">
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ py:strip="">
<py:def function="title(title_list=tmpl_context.title_list)">
High Availability Management
<py:if test="len(title_list) != 0"
12 years, 11 months
[luci] Fix rhbz#707918 - Luci doesn't allow subsequent service changes when non global filesystem resource
by Ryan McCabe
commit 4d18ab22fadc2c279e3485cb4d4a7988ce675b5b
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Jun 27 15:19:02 2011 -0400
Fix rhbz#707918 - Luci doesn't allow subsequent service changes when non global filesystem resource is added
luci/validation/validate_resource.py | 262 +++++++++++++++++-----------------
1 files changed, 131 insertions(+), 131 deletions(-)
---
diff --git a/luci/validation/validate_resource.py b/luci/validation/validate_resource.py
index 77fdd6d..9ec9812 100644
--- a/luci/validation/validate_resource.py
+++ b/luci/validation/validate_resource.py
@@ -523,6 +523,133 @@ def create_resource(res_type, model, **kw):
def validate_clusvc_form(model, **kw):
errors = list()
+ new_service = Service()
+ old_name = kw.get('old_name')
+ service_name = kw.get('svc_name')
+
+ action = kw.get('action')
+ if action is None:
+ errors.append(_('No action was given for service "%s"') % service_name)
+ return (False, {'errors': errors})
+
+ action = action.lower()
+ if action == 'edit':
+ cur_service = model.retrieveServiceByName(old_name)
+ if cur_service is None:
+ errors.append(_('The service "%s" could not be found for editing') % service_name)
+ return (False, {'errors': errors})
+ new_service.getAttributes().update(cur_service.getAttributes())
+ model.deleteService(service_name)
+ elif action == 'create':
+ cur_service = model.retrieveServiceByName(service_name)
+ if cur_service is not None:
+ errors.append(_('A cluster service with the name "%s" already exists') % service_name)
+ return (False, {'errors': errors})
+ else:
+ errors.append(_('An unknown action "%s" was specified') % action)
+ return (False, {'errors': errors})
+
+ if not service_name or service_name.isspace():
+ errors.append(_('No service name was given'))
+ return (False, {'errors': errors})
+ new_service.setName(service_name)
+
+ recovery = kw.get('recovery')
+ try:
+ new_service.setRecoveryPolicy(recovery)
+ except:
+ errors.append(_('Invalid recovery policy: %s') % recovery)
+
+ if new_service.getRecoveryPolicy() in ('restart', 'restart-disable'):
+ max_restarts = kw.get('max_restarts')
+ if max_restarts and not max_restarts.isspace():
+ try:
+ new_service.setMaxRestarts(max_restarts)
+ except:
+ errors.append(_('Maximum restarts must be a number greater than or equal to 0'))
+ else:
+ new_service.delMaxRestarts()
+
+ restart_expire_time = kw.get('restart_expire_time')
+ if restart_expire_time and not restart_expire_time.isspace():
+ try:
+ new_service.setRestartExpireTime(restart_expire_time)
+ except:
+ errors.append(_('Restart expire time must be a number greater than or equal to 0'))
+ else:
+ new_service.delRestartExpireTime()
+ else:
+ new_service.delMaxRestarts()
+ new_service.delRestartExpireTime()
+
+ fdom = kw.get('domain')
+ if fdom and not fdom.isspace():
+ new_service.setFailoverDomain(fdom)
+ else:
+ new_service.delFailoverDomain()
+
+ new_service.setAutostart(kw.get('autostart') is not None)
+
+ # In central processing mode, exclusive is an integer. When not in
+ # central processing mode, it's boolean.
+ ex_val = kw.get('exclusive')
+ if model.getResourceManagerPtr().getCentralProcessing() is True:
+ if ex_val and not ex_val.isspace():
+ try:
+ new_service.setExclusive(ex_val)
+ except:
+ errors.append(_('Invalid value specified for the exclusive property: %s') % ex_val)
+ else:
+ new_service.delExclusive()
+ else:
+ if ex_val is not None:
+ new_service.setExclusive(1)
+ else:
+ new_service.delExclusive()
+
+ if kw.get('expert_mode'):
+ new_service.setNFSLock(kw.get('nfslock') is not None)
+ new_service.setNFSClientCache(kw.get('nfs_client_cache') is not None)
+
+ cp_pri = kw.get('priority')
+ if cp_pri and not cp_pri.isspace():
+ try:
+ new_service.setPriority(cp_pri)
+ except:
+ errors.append(_('Invalid value for priority: %s') % cp_pri)
+ else:
+ new_service.delPriority()
+
+ svc_depend = kw.get('depend')
+ if svc_depend and not svc_depend.isspace():
+ test_name = svc_depend
+ if test_name.startswith('service:'):
+ test_name = test_name[8:]
+ elif test_name.startswith('vm:'):
+ test_name = test_name[3:]
+ else:
+ svc_depend = 'service:%s' % svc_depend
+
+ try:
+ test_svc = model.retrieveServiceByName(test_name)
+ if not test_svc:
+ errors.append(_('Invalid value for service dependency: %s: No such service exists') % test_name)
+ else:
+ new_service.setDepend(svc_depend)
+ except:
+ errors.append(_('Invalid value for service dependency: %s') % svc_depend)
+ else:
+ new_service.delDepend()
+
+ depend_mode = kw.get('depend_mode')
+ if depend_mode and not depend_mode.isspace():
+ try:
+ new_service.setDependMode(depend_mode)
+ except:
+ errors.append(_('Invalid dependency mode: %s') % depend_mode)
+ else:
+ new_service.delDependMode()
+
form_xml = kw.get('form_xml')
if not form_xml:
form_xml = ''
@@ -538,7 +665,7 @@ def validate_clusvc_form(model, **kw):
forms = doc.getElementsByTagName('form')
except:
log.exception('Error parsing service XML: "%s"' % form_xml)
- return (False, { 'errors': [ 'The resource data submitted for this service is not properly formed' ]})
+ return (False, { 'errors': [ _('The resource data submitted for this service is not properly formed') ]})
is_vm = False
form_hash = {}
@@ -583,7 +710,7 @@ def validate_clusvc_form(model, **kw):
is_vm = True
except Exception, e:
log.exception('no resource type')
- return (False, { 'errors': [ 'No resource type was specified' ]})
+ return (False, { 'errors': [ _('No resource type was specified') ]})
try:
if res_type == 'ip':
@@ -595,7 +722,7 @@ def validate_clusvc_form(model, **kw):
dummy_form['address'] = dummy_form['resourcename']
except:
log.exception('no ipaddr')
- return (False, { 'errors': [ 'No IP address was given' ]})
+ return (False, { 'errors': [ _('No IP address was given') ]})
try:
if dummy_form.has_key('global'):
@@ -616,7 +743,7 @@ def validate_clusvc_form(model, **kw):
log.exception('Error validating %s resource "%r"' % (res_type, dummy_form))
if not resObj:
- return (False, {'errors': errors})
+ continue
isubtree = True
if dummy_form.has_key('expert_mode'):
@@ -674,133 +801,6 @@ def validate_clusvc_form(model, **kw):
if len(errors) > 0:
return (False, {'errors': errors})
- new_service = Service()
- old_name = kw.get('old_name')
- service_name = kw.get('svc_name')
-
- action = kw.get('action')
- if action is None:
- errors.append(_('No action was given for service "%s"') % service_name)
- return (False, {'errors': errors})
-
- action = action.lower()
- if action == 'edit':
- cur_service = model.retrieveServiceByName(old_name)
- if cur_service is None:
- errors.append(_('The service "%s" could not be found for editing') % service_name)
- return (False, {'errors': errors})
- new_service.getAttributes().update(cur_service.getAttributes())
- model.deleteService(service_name)
- elif action == 'create':
- cur_service = model.retrieveServiceByName(service_name)
- if cur_service is not None:
- errors.append(_('A cluster service with the name "%s" already exists') % service_name)
- return (False, {'errors': errors})
- else:
- errors.append(_('An unknown action "%s" was specified') % action)
- return (False, {'errors': errors})
-
- if not service_name or service_name.isspace():
- errors.append(_('No service name was given'))
- return (False, {'errors': errors})
- new_service.setName(service_name)
-
- recovery = kw.get('recovery')
- try:
- new_service.setRecoveryPolicy(recovery)
- except:
- errors.append(_('Invalid recovery policy: %s') % recovery)
-
- if new_service.getRecoveryPolicy() in ('restart', 'restart-disable'):
- max_restarts = kw.get('max_restarts')
- if max_restarts and not max_restarts.isspace():
- try:
- new_service.setMaxRestarts(max_restarts)
- except:
- errors.append(_('Maximum restarts must be a number greater than or equal to 0'))
- else:
- new_service.delMaxRestarts()
-
- restart_expire_time = kw.get('restart_expire_time')
- if restart_expire_time and not restart_expire_time.isspace():
- try:
- new_service.setRestartExpireTime(restart_expire_time)
- except:
- errors.append(_('Restart expire time must be a number greater than or equal to 0'))
- else:
- new_service.delRestartExpireTime()
- else:
- new_service.delMaxRestarts()
- new_service.delRestartExpireTime()
-
- fdom = kw.get('domain')
- if fdom and not fdom.isspace():
- new_service.setFailoverDomain(fdom)
- else:
- new_service.delFailoverDomain()
-
- new_service.setAutostart(kw.get('autostart') is not None)
-
- # In central processing mode, exclusive is an integer. When not in
- # central processing mode, it's boolean.
- ex_val = kw.get('exclusive')
- if model.getResourceManagerPtr().getCentralProcessing() is True:
- if ex_val and not ex_val.isspace():
- try:
- new_service.setExclusive(ex_val)
- except:
- errors.append(_('Invalid value specified for the exclusive property: %s') % ex_val)
- else:
- new_service.delExclusive()
- else:
- if ex_val is not None:
- new_service.setExclusive(1)
- else:
- new_service.delExclusive()
-
- if kw.get('expert_mode'):
- new_service.setNFSLock(kw.get('nfslock') is not None)
- new_service.setNFSClientCache(kw.get('nfs_client_cache') is not None)
-
- cp_pri = kw.get('priority')
- if cp_pri and not cp_pri.isspace():
- try:
- new_service.setPriority(cp_pri)
- except:
- errors.append(_('Invalid value for priority: %s') % cp_pri)
- else:
- new_service.delPriority()
-
- svc_depend = kw.get('depend')
- if svc_depend and not svc_depend.isspace():
- test_name = svc_depend
- if test_name.startswith('service:'):
- test_name = test_name[8:]
- elif test_name.startswith('vm:'):
- test_name = test_name[3:]
- else:
- svc_depend = 'service:%s' % svc_depend
-
- try:
- test_svc = model.retrieveServiceByName(test_name)
- if not test_svc:
- errors.append(_('Invalid value for service dependency: %s: No such service exists') % test_name)
- else:
- new_service.setDepend(svc_depend)
- except:
- errors.append(_('Invalid value for service dependency: %s') % svc_depend)
- else:
- new_service.delDepend()
-
- depend_mode = kw.get('depend_mode')
- if depend_mode and not depend_mode.isspace():
- try:
- new_service.setDependMode(depend_mode)
- except:
- errors.append(_('Invalid dependency mode: %s') % depend_mode)
- else:
- new_service.delDependMode()
-
def buildSvcTree(parent, child_id_list):
for i in child_id_list:
try:
12 years, 11 months
[luci] Fix logic inversion typo in last patch (codepath hit on service groups detail section when viewing a
by Ryan McCabe
commit e83bd2460c6fedfb84cdd8903c7b3f0f28786dce
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Fri Jun 17 15:26:57 2011 -0400
Fix logic inversion typo in last patch (codepath hit on service groups detail section when viewing a VM)
luci/templates/service.html | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
---
diff --git a/luci/templates/service.html b/luci/templates/service.html
index 6d37796..68aeabe 100644
--- a/luci/templates/service.html
+++ b/luci/templates/service.html
@@ -156,7 +156,7 @@
</div>
<span class="details_header_info_label">Status</span> <span class="details_header_info">${tmpl_context.current_service_status}</span>
- <py:choose test="details and details.is_vm and details.running.lower() != 'true'">
+ <py:choose test="details and details.is_vm and details.running.lower() == 'true'">
<py:when test="True">
<input type="hidden" id="move_action" name="move_action" value="migrate"/>
<select id="preferred_node" style="font-size: small;" name="preferred_node" py:if="cluster_data">
12 years, 11 months
[luci] Fix migration of VMs from the Service Details page
by Ryan McCabe
commit ddbb3a56505e4025274f1f9986a440496b960d2a
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Fri Jun 17 15:25:51 2011 -0400
Fix migration of VMs from the Service Details page
luci/controllers/cluster.py | 27 +++++++++++++++++++++------
luci/lib/cluster_status.py | 6 ++++++
luci/public/js/service.js | 7 +++++++
luci/templates/service.html | 38 +++++++++++++++++++++++++++-----------
4 files changed, 61 insertions(+), 17 deletions(-)
---
diff --git a/luci/controllers/cluster.py b/luci/controllers/cluster.py
index 92ebbde..0fa3a0c 100644
--- a/luci/controllers/cluster.py
+++ b/luci/controllers/cluster.py
@@ -570,12 +570,27 @@ class IndividualClusterController(BaseController):
rh.update_cluster_conf(self.model)
redirect(tmpl_context.cluster_url)
if command == 'Start':
- log.info('User "%s" started service "%s" in cluster "%s"'
- % (self.username, ', '.join(cur_list), self.name))
- flash(_("Starting services %s") % ', '.join(cur_list),
- status='info')
- for i in cur_list:
- rh.cluster_svc_start(self.name, i, preferred_node)
+ move_action = kw.get('move_action')
+ if move_action == 'migrate':
+ 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)
+ 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))
+ rh.cluster_svc_migrate(self.name, vm_name, preferred_node)
+ else:
+ if preferred_node:
+ node_addendum = _(" on node %s") % preferred_node
+ else:
+ node_addendum = ''
+
+ log.info('User "%s" started service "%s"%s in cluster "%s"'
+ % (self.username, ', '.join(cur_list), node_addendum, self.name))
+ flash(_("Starting services %s%s") % (', '.join(cur_list), node_addendum), status='info')
+ for i in cur_list:
+ rh.cluster_svc_start(self.name, i, preferred_node)
elif command == 'Disable':
log.info('User "%s" disabled service "%s" in cluster "%s"'
% (self.username, ', '.join(cur_list), self.name))
diff --git a/luci/lib/cluster_status.py b/luci/lib/cluster_status.py
index 4609a8e..f441844 100644
--- a/luci/lib/cluster_status.py
+++ b/luci/lib/cluster_status.py
@@ -40,6 +40,12 @@ class NodeStatus:
class ServiceStatus:
def __init__(self, svc_xml):
self.type = 'service'
+ self.name = 'Unknown'
+ self.nodename = 'Unknown'
+ self.running = 'Unknown'
+ self.failed = 'Unknown'
+ self.autostart = 'Unknown'
+ self.is_vm = 'Unknown'
try:
self.name = svc_xml.getAttribute('name')
diff --git a/luci/public/js/service.js b/luci/public/js/service.js
index e95ab25..e2a8428 100644
--- a/luci/public/js/service.js
+++ b/luci/public/js/service.js
@@ -125,3 +125,10 @@ function update_restart_opts(recovery_policy) {
$(opt_elems).removeAttr('disabled', 'disabled');
}
}
+
+function move_service_group(baseurl) {
+ var move_action = $('#move_action').val();
+ var preferred_node = $('#preferred_node').val();
+
+ location.href = baseurl + '&preferred_node=' + preferred_node + '&move_action=' + move_action;
+}
diff --git a/luci/templates/service.html b/luci/templates/service.html
index 9b9b62a..6d37796 100644
--- a/luci/templates/service.html
+++ b/luci/templates/service.html
@@ -140,30 +140,46 @@
</div>
</py:when>
- <py:otherwise py:with="details = cluster_status.services.get(name)">
+ <py:otherwise
+ py:with="details = cluster_status.services.get(name);
+ svc = tmpl_context.cluster.get_model().getService(name)">
<!--! DETAILS - header section. -->
<div id="details_header">
<h3 py:content="name"/>
+ <form style="display: inline; padding-left: 24px; ">
<div id="details_header_buttons">
<a href="${tg.url(services_cmd + '?command=Delete' + '&name=' + name)}" id="dh_delete" title="delete"><span class="hide">delete</span></a>
<a href="${tg.url(services_cmd + '?command=Disable' + '&name=' + name)}" id="dh_stop" title="stop (disable)"><span class="hide">stop</span></a>
<a href="${tg.url(services_cmd + '?command=Restart' + '&name=' + name)}" id="dh_update" title="restart"><span class="hide">restart</span></a>
- <a href="${tg.url(services_cmd + '?command=Start' + '&name=' + name)}" id="dh_start" title="start"><span class="hide">start</span></a>
+ <a href="#" onclick="move_service_group('${tg.url(services_cmd + '?command=Start' + '&name=' + name)}')" id="dh_start" title="start"><span class="hide">start</span></a>
</div>
<span class="details_header_info_label">Status</span> <span class="details_header_info">${tmpl_context.current_service_status}</span>
- <form style="display: inline; padding-left: 24px; ">
- <select style="font-size: small;" name="preferred_node" py:if="cluster_data">
- <option value="">Start on node...</option>
- <py:for each="node in cluster_data.getNodeNames()" py:if="not details or node != details.nodename">
- <option value="node">${node}</option>
- </py:for>
- </select>
+
+ <py:choose test="details and details.is_vm and details.running.lower() != 'true'">
+ <py:when test="True">
+ <input type="hidden" id="move_action" name="move_action" value="migrate"/>
+ <select id="preferred_node" style="font-size: small;" name="preferred_node" py:if="cluster_data">
+ <option value="">Migrate to node...</option>
+ <py:for each="node in cluster_data.getNodeNames()" py:if="not details or node != details.nodename">
+ <option value="${node}">${node}</option>
+ </py:for>
+ </select>
+ </py:when>
+ <py:otherwise>
+ <input type="hidden" id="move_action" name="move_action" value="relocate"/>
+ <select id="preferred_node" style="font-size: small;" name="preferred_node" py:if="cluster_data">
+ <option value="">Start on node...</option>
+ <py:for each="node in cluster_data.getNodeNames()" py:if="not details or node != details.nodename">
+ <option value="${node}">${node}</option>
+ </py:for>
+ </select>
+ </py:otherwise>
+ </py:choose>
</form>
</div>
- <div id="edit_service_dialog"
- py:with="svc = tmpl_context.cluster.get_model().getService(name)">
+ <div id="edit_service_dialog">
<form
style="padding-left: 24px; "
name="edit_service_dialog" method="post" action="${tg.url(services_cmd + '?command=Edit')}">
12 years, 11 months
[luci] Fix rhbz #711625 - Unable to create a cluster of KVM guests
by Ryan McCabe
commit e850fe7953730e540c33b93d7fb2dc06bb26d451
Author: Ryan McCabe <rmccabe(a)redhat.com>
Date: Mon Jun 13 15:43:10 2011 -0400
Fix rhbz #711625 - Unable to create a cluster of KVM guests
luci/lib/ClusterConf/BaseResource.py | 20 ++++++++++++++------
luci/lib/ClusterConf/Service.py | 3 +++
luci/lib/ClusterConf/Vm.py | 5 +++--
luci/templates/resource_list.html | 10 +++++-----
luci/validation/validate_resource.py | 34 ++++++++++++++--------------------
5 files changed, 39 insertions(+), 33 deletions(-)
---
diff --git a/luci/lib/ClusterConf/BaseResource.py b/luci/lib/ClusterConf/BaseResource.py
index c91f610..9513d44 100644
--- a/luci/lib/ClusterConf/BaseResource.py
+++ b/luci/lib/ClusterConf/BaseResource.py
@@ -91,20 +91,28 @@ class BaseResource(TagObject):
def delFailureExpireTime(self):
return self.removeAttribute('__failure_expire_time')
- def getMaxRestarts(self):
+ def getResMaxRestarts(self):
return self.getAttribute('__max_restarts')
- def setMaxRestarts(self, val):
+ def setResMaxRestarts(self, val):
return self.addIntegerAttribute('__max_restarts', val, (0, None))
- def delMaxRestarts(self):
+ def delResMaxRestarts(self):
return self.removeAttribute('__max_restarts')
- def getRestartExpireTime(self):
+ def getResRestartExpireTime(self):
return self.getAttribute('__restart_expire_time')
- def setRestartExpireTime(self, val):
+ def setResRestartExpireTime(self, val):
return self.addIntegerAttribute('__restart_expire_time', val, (0, None))
- def delRestartExpireTime(self):
+ def delResRestartExpireTime(self):
return self.removeAttribute('__restart_expire_time')
+
+ def delSubtreeProperties(self):
+ self.delIndependentSubtree()
+ self.delEnforceTimeouts()
+ self.delMaxFailures()
+ self.delFailureExpireTime()
+ self.delResMaxRestarts()
+ self.delResRestartExpireTime()
diff --git a/luci/lib/ClusterConf/Service.py b/luci/lib/ClusterConf/Service.py
index c94c27e..698368b 100644
--- a/luci/lib/ClusterConf/Service.py
+++ b/luci/lib/ClusterConf/Service.py
@@ -34,6 +34,9 @@ class Service(TagObject):
def getExclusive(self):
return self.getAttribute('exclusive')
+ def getExclusiveBinary(self):
+ return self.getBinaryAttribute('exclusive')
+
def setExclusive(self, val):
return self.addIntegerAttribute('exclusive', val, (0, None))
diff --git a/luci/lib/ClusterConf/Vm.py b/luci/lib/ClusterConf/Vm.py
index 49cd131..62009a8 100644
--- a/luci/lib/ClusterConf/Vm.py
+++ b/luci/lib/ClusterConf/Vm.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2010 Red Hat, Inc.
+# Copyright (C) 2006-2011 Red Hat, Inc.
#
# This program is free software; you can redistribute
# it and/or modify it under the terms of version 2 of the
@@ -6,10 +6,11 @@
# Free Software Foundation.
from Service import Service
+from BaseResource import BaseResource
TAG_NAME = "vm"
-class Vm(Service):
+class Vm(Service, BaseResource):
def __init__(self):
Service.__init__(self)
self.TAG_NAME = TAG_NAME
diff --git a/luci/templates/resource_list.html b/luci/templates/resource_list.html
index 9f2547e..c0623ea 100644
--- a/luci/templates/resource_list.html
+++ b/luci/templates/resource_list.html
@@ -37,28 +37,28 @@
<td>Maximum number of failures</td>
<td>
<input type="text" class="text subtree" name="__max_failures"
- py:attrs="res and {'value':res.getAttribute('__max_failures')} or {}"/>
+ py:attrs="res and {'value':res.getMaxFailures()} or {}"/>
</td>
</tr>
<tr>
<td>Failure expire time (seconds)</td>
<td>
<input type="text" class="text subtree" name="__failure_expire_time"
- py:attrs="res and {'value':res.getAttribute('__failure_expire_time')} or {}"/>
+ py:attrs="res and {'value':res.getFailureExpireTime()} or {}"/>
</td>
</tr>
<tr>
<td>Maximum number of restarts</td>
<td>
<input type="text" class="text subtree" name="__max_restarts"
- py:attrs="res and {'value':res.getAttribute('__max_restarts')} or {}"/>
+ py:attrs="res and {'value':res.getResMaxRestarts()} or {}"/>
</td>
</tr>
<tr>
<td>Restart expire time (seconds)</td>
<td>
<input type="text" class="text subtree" name="__restart_expire_time"
- py:attrs="res and {'value':res.getAttribute('__restart_expire_time')} or {}"/>
+ py:attrs="res and {'value':res.getResRestartExpireTime()} or {}"/>
</td>
</tr>
</table>
@@ -1797,7 +1797,7 @@ ${vm_resource(None,None,None,0)}
<input py:if="central_processing" type="text" class="text"
py:attrs="svc and {'value':svc.getExclusive()} or {}"/>
<input py:if="not central_processing" type="checkbox" class="checkbox" name="exclusive"
- py:attrs="(svc and svc.getExclusive()) and {'checked': 'checked'} or {}"/>
+ py:attrs="(svc and svc.getExclusiveBinary()) and {'checked': 'checked'} or {}"/>
</td>
</tr>
<tr>
diff --git a/luci/validation/validate_resource.py b/luci/validation/validate_resource.py
index 1c5b3ce..77fdd6d 100644
--- a/luci/validation/validate_resource.py
+++ b/luci/validation/validate_resource.py
@@ -7,6 +7,7 @@
from luci.lib.ClusterConf.Ip import Ip
from luci.lib.ClusterConf.Fs import Fs
+from luci.lib.ClusterConf.BaseResource import BaseResource
from luci.lib.ClusterConf.Clusterfs import Clusterfs
from luci.lib.ClusterConf.Netfs import Netfs
from luci.lib.ClusterConf.NFSExport import NFSExport
@@ -494,9 +495,10 @@ def create_resource(res_type, model, **kw):
res = resource_table[res_type][1]()
if res_type == 'ip':
- rname = kw['address']
+ rname = kw.get('address')
elif res_type == 'vm':
rname = ''
+ res = BaseResource()
else:
if not kw.has_key('resourcename') or not kw['resourcename'].strip():
raise Exception, _('All resources must have a unique name.')
@@ -626,32 +628,27 @@ def validate_clusvc_form(model, **kw):
else:
# These do not apply if __independent_subtree is not 1 or 2
isubtree = False
- resObj.delIndependentSubtree()
- resObj.delNonCriticalResource()
- resObj.delMaxRestarts()
- resObj.delRestartExpireTime()
- resObj.delMaxFailures()
- resObj.delFailureExpireTime()
+ resObj.delSubtreeProperties()
if isubtree is True:
max_restarts = dummy_form.get('__max_restarts')
if max_restarts and not max_restarts.isspace():
try:
- resObj.setMaxRestarts(max_restarts)
+ resObj.setResMaxRestarts(max_restarts)
except:
errors.append(_('Invalid value for max restarts for %s: %s') % (cur_res_name, max_restarts))
else:
- resObj.delMaxRestarts()
- resObj.delRestartExpireTime()
+ resObj.delResMaxRestarts()
+ resObj.delResRestartExpireTime()
restart_expire_time = dummy_form.get('__restart_expire_time')
if restart_expire_time and not restart_expire_time.isspace():
try:
- resObj.setRestartExpireTime(restart_expire_time)
+ resObj.setResRestartExpireTime(restart_expire_time)
except:
errors.append(_('Invalid value for restart expire time for %s: %s') % (cur_res_name, restart_expire_time))
else:
- resObj.delRestartExpireTime()
+ resObj.delResRestartExpireTime()
max_failures = dummy_form.get('__max_failures')
if max_failures and not max_failures.isspace():
@@ -820,17 +817,14 @@ def validate_clusvc_form(model, **kw):
buildSvcTree(new_service, form_hash[root_elem]['kids'])
if is_vm is True:
- new_vm = Vm()
svc_children = new_service.getChildren()
if len(svc_children) != 1:
- errors.append(_('VMs may have no children and may not be children of resources'))
+ errors.append(_('VMs can have no children and cannot be children of resources'))
else:
- vm_res = svc_children[0]
- vm_attr = vm_res.getAttributes()
- vm_attr.update(new_service.getAttributes())
- for k, v in vm_attr.items():
- new_vm.addAttribute(k, v)
- model.resourcemanager_ptr.addChild(new_vm)
+ new_vm = Vm()
+ new_vm.getAttributes().update(new_service.getAttributes())
+ new_vm.getAttributes().update(svc_children[0].getAttributes())
+ model.resourcemanager_ptr.addChild(new_vm)
else:
model.resourcemanager_ptr.addChild(new_service)
return (len(errors) == 0, {'errors': errors})
12 years, 11 months