[libvirt] [PATCH] libvirt-guests: Enable parallel operations and improve error handling
Eric Blake
eblake at redhat.com
Tue Feb 21 00:31:09 UTC 2012
On 02/20/2012 06:32 AM, Peter Krempa wrote:
> This patch modifies the libvirt-guests init script to enable parallel
> shiutdown on guest machines and gets rid of error messages if the client
s/shiutdown/shutdown/
> is unable connect to the URI specified in the config file.
> ---
> Simultaneous shutdown of machines may speed up the shutdown process as the shutdown sequence
> of guests often consists of timeouts and storage un-intensive tasks. Simultaneous resume
> of machines was already supported, although not documented well enough.
>
> This patch also checks if connection to the URI can be done, and prints a error
> message if it's not the case. This get's rid of unrelevant and repeated error messages
s/unrelevant/irrelevant/
(Stupid English, for being inconsistent on whether un- or ir- negates a
word :)
> if the URI is unreachable.
>
> The last improvement is while using managed-save. Transient domains are excluded
> from the save sequence to get rid of error messages and a list of domains that are left
> behind is printed.
>
> Please tell me your suggestions how to improve this, as I'm not a bash "native speaker".
Actually, we want this to be stricter than bash, since people are using
libvirt-guests on debian-based systems where /bin/sh is dash. But no
fears - I'm fluent in shell.
>
> +test_connect()
I find it helpful to document ALL shell functions; it makes maintenance
easier down the road (it doesn't help that we haven't been doing this in
the rest of the file). Here, it looks like you are doing:
# test_connect URI
# check if URI is reachable
test_connect() {
> +{
> + uri=$1
> +
> + run_virsh "$uri" connect 2>/dev/null
Any reason for the two spaces?
> + if [ $? -ne 0 ]; then
> + eval_gettext "Can't connect to \$uri. Skipping."
> + echo
> + return 1
> + fi
> +}
> +
> +# "persistent" argument options:
> +# yes: list only persistent guests
> +# no: list only transient guests
> +# all: list both persistent and transient guests
> list_guests() {
Here, I would use:
# list_guests URI PERSISTENT
prior to the documentation of valid PERSISTENT values.
> uri=$1
> + persistent=$2
>
> list=$(run_virsh_c "$uri" list)
> if [ $? -ne 0 ]; then
> @@ -89,12 +106,19 @@ list_guests() {
>
> uuids=
> for id in $(echo "$list" | awk 'NR > 2 {print $1}'); do
> - uuid=$(run_virsh_c "$uri" dominfo "$id" | awk '/^UUID:/{print $2}')
<aside>
Remind me again why we are doing an inefficient shell loop? In fact,
why were we using 'dominfo | awk' to convert id to uuid? It's faster to
use 'run_virsh_c "$uri" virsh domuuid $id" to get the same information.
Taking it one step further, I'd rather see us enhance 'virsh list' to
give us what we want up front. That is, I think it would be nice to
have 'virsh list { [--table] | --uuid | --name | --id } ...', where
--table is default (for back-compat), but listing --uuid, --name, or
--id drops the header line, and lists just one identifier per line
rather than a full table. Also, I'd also like to see 'virsh list {
[--running] | --all | --inactive | --persistent | --transient } ...';
that is, we ought to have virsh list fine-tune which domains it lists,
by adding new options such as --persistent and --transient.
By improving virsh, we could skip out on the awk loop altogether, and
have the initial virsh list give us what we want in the first place.
</aside>
> - if [ -z "$uuid" ]; then
> + dominfo=$(run_virsh_c "$uri" dominfo "$id")
> + uuid=$(echo "$dominfo" | awk '/^UUID:/{print $2}')
> + dompersist=$(echo "$dominfo" | awk '/^Persistent:/{print $2}')
This sets $dompersist to yes or no,...
> +
> + if [ -z "$uuid" ] || [ -z "$dompersist" ]; then
> RETVAL=1
> return 1
> fi
> - uuids="$uuids $uuid"
> +
> + if [ "$persistent" == "$dompersist" ] ||
For portability to dash, you must use '=', not '==', inside [].
> + [ "$persistent" == "all" ]; then
> + uuids="$uuids $uuid"
...if persistent is 'all', then you wasted an awk call above for a
result you don't care about, since you plan on using the uuid anyway.
Again, more reason to have virsh list give us what we want in the first
place.
>
> +shutdown_guest_async()
> +{
> + uri=$1
> + guest=$2
> +
> + name=$(guest_name "$uri" "$guest")
> + label=$(eval_gettext "Starting shutdown on guest: \$name")
> + echo $label
Missing quotes around $label. Probably simpler to just:
name=$(guest_name "$uri" "$guest")
eval_gettext "Starting shutdown on guest: \$name"
echo
> + retval run_virsh "$uri" shutdown "$guest" >/dev/null || return
No need for the ||return - since this is the last statement in the
function, you will return anyway, with the same status.
> +}
> +
> +set_add()
> +{
> + item=$1
> + items=$2
> +
> + echo "$items $item"
Should you be checking for duplicates before adding into a set? I'm not
sure without reviewing further to see how this is used. Also, this
particular usage requires that the user capture the output of the shell
function using $(), which wastes a subshell; there are tricks for
passing the name of a variable which holds a set, where you can then
modify the variable in place with fewer forks, but I don't think we're
at the point where optimizing a few forks will help matters.
> +}
> +
> +set_remove()
> +{
> + item=$1
> + items=$2
> +
> + newitems=
> + for nit in $items; do
> + if [ "$nit" != "$domain" ]; then
Where did "$domain" come from? Don't you instead mean to be comparing
against "$item"?
> + newitems="$newitems $nit"
The resulting $newitems will always have a leading space, even if $items
on entry did not. Is that intentional?
> + fi
> + done
> +
> + echo "$newitems"
> +}
> +
> +set_count()
> +{
> + items=$1
> +
> + count="0"
> + for item in $items; do
> + count=$((count+1))
It's slightly more portable to do $(($count+1)). But even that is slow;
why not let the shell do it for you:
set_count() {
set -- $1
echo $#
}
> + done
> +
> + echo $count
> +}
> +
> +set_head()
> +{
> + items=$1
> +
> + for item in $items; do
> + echo $item
> + return 0
> + done
> +}
I sure hope that the sets you are using have no whitespace or glob
characters (that is, a set of domain ids or uuids is safe, a set of
domain names or of URIs is not).
> +
> +remove_shutdown_domains()
> +{
> + uri=$1
> + domains=$2
> +
> + newlist=
> + for dom in $domains; do
> + guest_is_on "$uri" "$dom" 2>&1 > /dev/null || return
Do you really want to break out of the entire for loop on the first
guest where you encounter failure? Also, this redirection looks fishy -
it says 'make the error output of guest_is_on go to my stdout, and
discard the normal output of guest_is_on'. Did you mean '>/dev/null
2>&1' which says to discard both output and error messages from guest_is_on?
> + if "$guest_running"; then
> + newlist="$newlist $dom"
> + fi
> + done
> +
> + echo "$newlist"
> +}
I ran out of time to finish my review today, but hope this gives you
some things to think about.
--
Eric Blake eblake at redhat.com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 620 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20120220/85b5402c/attachment-0001.sig>
More information about the libvir-list
mailing list