Patchwork [v2,2/2] qemu-ga: sample fsfreeze hooks

login
register
mail settings
Submitter Tomoki Sekiyama
Date Nov. 12, 2012, 9:32 a.m.
Message ID <20121112093258.20398.52001.stgit@melchior2.sdl.hitachi.co.jp>
Download mbox | patch
Permalink /patch/198341/
State New
Headers show

Comments

Tomoki Sekiyama - Nov. 12, 2012, 9:32 a.m.
Adds sample hook scripts for --fsfreeze-hook option of qemu-ga.
  - fsfreeze-hook : execute scripts in fsfreeze-hook.d/
  - fsfreeze-hook.d.sample/mysql-flush.sh : quiesce MySQL before snapshot

Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com>
---
 docs/qemu-guest-agent/fsfreeze-hook                |   31 +++++++++++++
 .../fsfreeze-hook.d.sample/mysql-flush.sh          |   47 ++++++++++++++++++++
 2 files changed, 78 insertions(+)
 create mode 100755 docs/qemu-guest-agent/fsfreeze-hook
 create mode 100755 docs/qemu-guest-agent/fsfreeze-hook.d.sample/mysql-flush.sh
Eric Blake - Nov. 12, 2012, 10:16 p.m.
On 11/12/2012 02:32 AM, Tomoki Sekiyama wrote:
> Adds sample hook scripts for --fsfreeze-hook option of qemu-ga.
>   - fsfreeze-hook : execute scripts in fsfreeze-hook.d/
>   - fsfreeze-hook.d.sample/mysql-flush.sh : quiesce MySQL before snapshot
> 
> Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com>
> ---

> +LOGFILE=/var/log/qga-fsreeze-hook.log

s/fsreeze/fsfreeze/

> +# Iterate executables in directory "fsfreeze-hook.d" with the specified args
> +[ ! -d "$FSFREEZE_D" ] && exit 1
> +for file in "$FSFREEZE_D"/* ; do
> +    is_ignored_file "$file" && continue
> +    [ -x "$file" ] || continue
> +    echo $(date) ": execute $file $@" >>$LOGFILE

Put $(date) inside the ""; otherwise, single-digit days will be one
character shorter due to IFS field splitting eating the double-space;
and I don't like unaligned dates in logs.

> +    "$file" "$@" >>$LOGFILE 2>&1
> +    STATUS=$?
> +    echo $(date) ": $file finished with status=$STATUS" >>$LOGFILE

and again.

> +        INNODB_STATUS=$(mktemp /tmp/mysql-flush.XXXXXX)
> +        [ $? -ne 0 ] && exit 2
> +        trap "rm -f $INNODB_STATUS" SIGINT
> +        while :; do
> +            echo 'SHOW ENGINE INNODB STATUS \G' | $MYSQL > $INNODB_STATUS

'echo' cannot portably be used with \.  Use 'printf' instead.
Tomoki Sekiyama - Nov. 13, 2012, 4:49 a.m.
Hi Eric,
thank you for the review again.

On 2012/11/13 7:16, Eric Blake wrote:
> On 11/12/2012 02:32 AM, Tomoki Sekiyama wrote:
>> Adds sample hook scripts for --fsfreeze-hook option of qemu-ga.
>>   - fsfreeze-hook : execute scripts in fsfreeze-hook.d/
>>   - fsfreeze-hook.d.sample/mysql-flush.sh : quiesce MySQL before snapshot
>>
>> Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama.qu@hitachi.com>
>> ---
> 
>> +LOGFILE=/var/log/qga-fsreeze-hook.log
> 
> s/fsreeze/fsfreeze/

Oops...

>> +# Iterate executables in directory "fsfreeze-hook.d" with the specified args
>> +[ ! -d "$FSFREEZE_D" ] && exit 1
>> +for file in "$FSFREEZE_D"/* ; do
>> +    is_ignored_file "$file" && continue
>> +    [ -x "$file" ] || continue
>> +    echo $(date) ": execute $file $@" >>$LOGFILE
> 
> Put $(date) inside the ""; otherwise, single-digit days will be one
> character shorter due to IFS field splitting eating the double-space;
> and I don't like unaligned dates in logs.
> 
>> +    "$file" "$@" >>$LOGFILE 2>&1
>> +    STATUS=$?
>> +    echo $(date) ": $file finished with status=$STATUS" >>$LOGFILE
> 
> and again.

I will fix this.

>> +        INNODB_STATUS=$(mktemp /tmp/mysql-flush.XXXXXX)
>> +        [ $? -ne 0 ] && exit 2
>> +        trap "rm -f $INNODB_STATUS" SIGINT
>> +        while :; do
>> +            echo 'SHOW ENGINE INNODB STATUS \G' | $MYSQL > $INNODB_STATUS
> 
> 'echo' cannot portably be used with \.  Use 'printf' instead.

OK, I replace this with 'printf' (also in 'flush_and_wait' function).

Patch

diff --git a/docs/qemu-guest-agent/fsfreeze-hook b/docs/qemu-guest-agent/fsfreeze-hook
new file mode 100755
index 0000000..efc9bf2
--- /dev/null
+++ b/docs/qemu-guest-agent/fsfreeze-hook
@@ -0,0 +1,31 @@ 
+#!/bin/sh
+
+# This script is executed when a guest agent receives fsfreeze-freeze and
+# fsfreeze-thaw command, if it is specified in --fsfreeze-hook (-F)
+# option of qemu-ga or placed in default path (/etc/qemu/fsfreeze-hook).
+# When the agent receives fsfreeze-freeze request, this script is issued with
+# "freeze" argument before the filesystem is freezed. And for fsfreeze-thaw
+# request, it is issued with "thaw" argument after filesystem is thawed.
+
+LOGFILE=/var/log/qga-fsreeze-hook.log
+FSFREEZE_D=$(dirname -- "$0")/fsfreeze-hook.d
+
+# Check whether file $1 is a backup or rpm-generated file and should be ignored
+is_ignored_file() {
+    case "$1" in
+        *~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave)
+            return 0 ;;
+    esac
+    return 1
+}
+
+# Iterate executables in directory "fsfreeze-hook.d" with the specified args
+[ ! -d "$FSFREEZE_D" ] && exit 1
+for file in "$FSFREEZE_D"/* ; do
+    is_ignored_file "$file" && continue
+    [ -x "$file" ] || continue
+    echo $(date) ": execute $file $@" >>$LOGFILE
+    "$file" "$@" >>$LOGFILE 2>&1
+    STATUS=$?
+    echo $(date) ": $file finished with status=$STATUS" >>$LOGFILE
+done
diff --git a/docs/qemu-guest-agent/fsfreeze-hook.d.sample/mysql-flush.sh b/docs/qemu-guest-agent/fsfreeze-hook.d.sample/mysql-flush.sh
new file mode 100755
index 0000000..705002e
--- /dev/null
+++ b/docs/qemu-guest-agent/fsfreeze-hook.d.sample/mysql-flush.sh
@@ -0,0 +1,47 @@ 
+#!/bin/sh
+
+# Flush MySQL tables to the disk before the filesystem is freezed.
+# At the same time, this keeps a read lock while the filesystem is freezed
+# in order to avoid write accesses by the other clients.
+
+MYSQL="mysql -uroot" #"-prootpassword"
+FIFO=/tmp/mysql-flush.fifo
+
+flush_and_wait() {
+    echo 'FLUSH TABLES WITH READ LOCK \G'
+    read < $FIFO
+    echo 'UNLOCK TABLES \G'
+}
+
+case "$1" in
+    freeze)
+        mkfifo $FIFO || exit 1
+        flush_and_wait | $MYSQL &
+        # wait until every block is flushed
+        while [ "$(echo 'SHOW STATUS LIKE "Key_blocks_not_flushed"' |\
+                 $MYSQL | tail -1 | cut -f 2)" -gt 0 ]; do
+            sleep 1
+        done
+        # for InnoDB, wait until every log is flushed
+        INNODB_STATUS=$(mktemp /tmp/mysql-flush.XXXXXX)
+        [ $? -ne 0 ] && exit 2
+        trap "rm -f $INNODB_STATUS" SIGINT
+        while :; do
+            echo 'SHOW ENGINE INNODB STATUS \G' | $MYSQL > $INNODB_STATUS
+            LOG_CURRENT=$(grep 'Log sequence number' $INNODB_STATUS |\
+                          tr -s ' ' | cut -d' ' -f4)
+            LOG_FLUSHED=$(grep 'Log flushed up to' $INNODB_STATUS |\
+                          tr -s ' ' | cut -d' ' -f5)
+            [ "$LOG_CURRENT" = "$LOG_FLUSHED" ] && break
+            sleep 1
+        done
+        rm -f $INNODB_STATUS
+        ;;
+
+    thaw)
+        [ ! -p $FIFO ] && exit 1
+        echo > $FIFO
+        rm $FIFO
+        ;;
+esac
+