Bug 1142693

Summary: [RFE] Add a qemu resume hook that is able to preprocess the domain XML
Product: Red Hat Enterprise Linux 7 Reporter: Martin Sivák <msivak>
Component: libvirtAssignee: Peter Krempa <pkrempa>
Status: CLOSED ERRATA QA Contact: Virtualization Bugs <virt-bugs>
Severity: high Docs Contact:
Priority: unspecified    
Version: 7.1CC: agedosier, berrange, clalancette, dyuan, extras-qa, honzhang, itamar, jforbes, laine, libvirt-maint, lmiksik, msivak, mzhan, pkrempa, rbalakri, veillard, virt-maint
Target Milestone: rcKeywords: FutureFeature
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: libvirt-1.2.8-6.el7 Doc Type: Enhancement
Doc Text:
Feature: Libvirt supports custom operation hooks for various operations that allows to modify the guest XML in case custom actions are needed before the actions take place. This feature now allows to add a guest hook when a guest vm save image is resumed. Reason: A specific use case requested for the guest XML to be tweaked before a VM is resumed. Result: Users are now able to add a hook when a VM is about to be resumed to process the XML or react on the event.
Story Points: ---
Clone Of: 1142684 Environment:
Last Closed: 2015-03-05 07:44:41 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 1142684    
Bug Blocks:    

Description Martin Sivák 2014-09-17 08:31:24 UTC
+++ This bug was initially created as a clone of Bug #1142684 +++

Description of problem:

We would like to be able to preprocess the XML that is used when domain is resumed. It should work very similarly to how migrate hook does.

Rationale:

The min_guarantee change (ignore -> fail) affects long running VMs. We can workaround this by making sure the offending element is removed from the XML during migration or resume.

Currently only migration destination allows us to do that, but if a VM is never migrated, then suspended and resumed on host with new enough libvirt - it will fail to start.

Comment 2 Peter Krempa 2014-09-22 15:27:14 UTC
Added upstream:

commit 4f3c2e39e5c898c533ddf58b62b452a674df794d
Author: Peter Krempa <pkrempa>
Date:   Wed Sep 17 11:38:39 2014 +0200

    qemu: hook: Provide hook when restoring a domain save image

(and a few refactors before that).

v1.2.8-218-g4f3c2e3

Comment 5 hongming 2014-10-22 07:56:02 UTC
Hi Peter

If add a qemu hook with empty output, it is failed to restore domain .

But according to the following doc , The domain should be successfully restored. 
"Empty output is identical to copying the input XML without changing it."

# cat /etc/libvirt/hooks/qemu
#! /usr/bin/python
import sys
import os
hooklog = '/tmp/hook.log'
log = open(hooklog, 'w')

def read_in():
    lines = sys.stdin.readlines()
    for i in range(len(lines)):
        log.write(lines[i])

def main():
    if sys.argv[1] == 'r7' and sys.argv[2] == 'restore':
        read_in()

if __name__ == '__main__':
    main()


# virsh start r7
Domain r7 started

# virsh save r7 r7.save

Domain r7 saved to r7.save

[root@localhost images]# virsh restore r7.save
error: Failed to restore domain from r7.save
error: (domain_definition):1: Document is empty
(null)
^

[root@localhost images]# cat /tmp/hook.log
<domain type='kvm'>
  <name>r7</name>
  <uuid>1eff705e-a316-42f4-92c9-262d14322f72</uuid>
  <memory unit='KiB'>1048576</memory>
  <currentMemory unit='KiB'>1048576</currentMemory>
  <vcpu placement='static'>1</vcpu>

  ...... 

</domain>

Comment 6 Peter Krempa 2014-10-22 08:14:28 UTC
Hmm, yes. Unfortunately the hook execution code returns a string buffer for the output even if the output was empty. The buffer needs to be checked for contents.

I need to fix the issue upstream.

Comment 7 Peter Krempa 2014-10-22 16:30:27 UTC
Fixed upstream with:

commit e38677993734e9af3dbd0589e1cecd0b75f7e757
Author: Peter Krempa <pkrempa>
Date:   Wed Oct 22 11:22:08 2014 +0200

    qemu: restore: Fix restoring of VM when the restore hook returns empty XML
    
    The documentation for the restore hook states that returning an empty
    XML is equivalent with copying the input. There was a bug in the code
    checking the returned string by checking the string instead of the
    contents. Use the new helper to check if the string is empty.

commit 0eeafeedebe4469fce33d7942551957853856619
Author: Peter Krempa <pkrempa>
Date:   Wed Oct 22 10:26:42 2014 +0200

    util: string: Add helper to check whether string is empty
    
    The helper checks whether a string contains only whitespace or is NULL.
    This will be helpful to skip cases where a user string is optional, but
    may be provided empty with the same meaning.

Comment 10 hongming 2014-11-05 08:59:06 UTC
Verify it as follows.

1. Test a qemu hook with empty output

# rpm -q libvirt
libvirt-1.2.8-6.el7.x86_64

# cat /etc/libvirt/hooks/qemu
#! /bin/bash
if [ $1 = r7 -a $2 = restore ]; then
    echo "$0" "$@" >> /tmp/qemu.log
fi
exit 0

# virsh start r7
Domain r7 started


# cat /tmp/qemu.log

# virsh save r7 r7.save
Domain r7 saved to r7.save

# virsh restore r7.save
Domain restored from r7.save

# cat /tmp/qemu.log 
/etc/libvirt/hooks/qemu r7 restore begin -

=============================================================================

2. Test a qemu hook for modifying boot order when restoring a domain

# cat /etc/libvirt/hooks/qemu
#! /usr/bin/python
import sys

def input_xml():
    xml = ""
    lines = sys.stdin.readlines()
    xml = "".join(lines)
    xml = xml.replace("<source file='/var/lib/libvirt/images/r7.img'/>\n" , "<source file='/r7.img'/>\n")
    sys.stdout.write(xml)

def main():
    if sys.argv[1] == 'r7' and sys.argv[2] == 'restore':
        input_xml()

if __name__ == '__main__':
    main()

# virsh list
 Id    Name                           State
----------------------------------------------------
 5     r7                             running

# virsh save r7 r7.save
Domain r7 saved to r7.save

# virsh dumpxml r7|grep 'source file'
      <source file='/var/lib/libvirt/images/r7.img'/>
# cp /var/lib/libvirt/images/r7.img  /r7.img

# virsh restore r7.save
Domain restored from r7.save

# virsh dumpxml r7|grep 'source file'
      <source file='/r7.img'/>

Comment 11 hongming 2014-11-05 09:03:37 UTC
> 
> 2. Test a qemu hook for modifying boot order when restoring a domain

Sorry. the scenario2 is actually modifying disk path when restoring a domain. The result in Comment 10 is expected.

Comment 12 hongming 2014-11-05 09:17:03 UTC
Add a verification for restoring a managed save domain.

1. Test a qemu hook with empty output when restoring managedsaved domain
# cat /etc/libvirt/hooks/qemu
#! /bin/bash
if [ $1 = r7 -a $2 = restore ]; then
    echo "$0" "$@" >> /tmp/qemu.log
fi
exit 0

# virsh managedsave r7

Domain r7 state saved by libvirt

# cat /tmp/qemu.log

# virsh start r7
Domain r7 started

# cat /tmp/qemu.log
/etc/libvirt/hooks/qemu r7 restore begin -

================================================================================

2. Test a qemu hook for modifying disk path when restoring a managedsaved domain

# cat /etc/libvirt/hooks/qemu
#! /usr/bin/python
import sys

def input_xml():
    xml = ""
    lines = sys.stdin.readlines()
    xml = "".join(lines)
    xml = xml.replace("<source file='/var/lib/libvirt/images/r7.img'/>\n" , "<source file='/r7.img'/>\n")
    sys.stdout.write(xml)

def main():
    if sys.argv[1] == 'r7' and sys.argv[2] == 'restore':
        input_xml()

if __name__ == '__main__':
    main()


# virsh list
 Id    Name                           State
----------------------------------------------------
 9     r7                             running

# virsh managedsave r7

Domain r7 state saved by libvirt

# virsh dumpxml r7|grep 'source file'
      <source file='/var/lib/libvirt/images/r7.img'/>

# cp /var/lib/libvirt/images/r7.img  /r7.img

# virsh start r7
Domain r7 started

# virsh dumpxml r7|grep 'source file'
      <source file='/r7.img'/>

Comment 13 hongming 2015-01-27 03:46:47 UTC
Hi  Martin 

The resume and restore are different operations in libvirt. The restore hook only is called when restoring a saved image. It can't be called when resuming a suspended domain. Please review the following results.  Is it your expected result ?


# cat /etc/libvirt/hooks/qemu
#! /bin/bash
if [ $1 = r7 -a $2 = restore ]; then
    echo "$0" "$@" >> /tmp/qemu.log
fi
exit 0

# virsh save r7 r7.save

Domain r7 saved to r7.save

# virsh restore r7.save
Domain restored from r7.save

# cat /tmp/qemu.log
/etc/libvirt/hooks/qemu r7 restore begin -

# > /tmp/qemu.log

# virsh suspend r7
Domain r7 suspended

# virsh resume r7
Domain r7 resumed

# cat /tmp/qemu.log

#

Comment 15 errata-xmlrpc 2015-03-05 07:44:41 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://rhn.redhat.com/errata/RHSA-2015-0323.html