Exemplo n.º 1
0
def create_attach_xml(update_xmlfile,
                      disk_type,
                      target_bus,
                      target_dev,
                      source_iso="",
                      disk_mode=""):
    """
    Create a xml file to update a device.

    :param update_xmlfile : path/file to save device XML
    :param source_iso : disk's source backing file.
    :param disk_type: disk's device type: cdrom or floppy
    :param target_bus: disk's target bus
    :param target_dev: disk's target device name
    :param disk_mode: readonly or shareable
    """
    if source_iso:
        libvirt.create_local_disk("iso", source_iso)
    disk_class = VMXML.get_device_class('disk')
    disk = disk_class(type_name='file')
    # Static definition for comparison in check_attach()
    disk.device = disk_type
    disk.target = dict(bus=target_bus, dev=target_dev)
    if source_iso:
        disk.driver = dict(name='qemu')
        disk.source = disk.new_disk_source(attrs={'file': source_iso})
        if disk_mode == "readonly":
            disk.readonly = True
        if disk_mode == "shareable":
            disk.share = True
    disk.xmltreefile.write()
    shutil.copyfile(disk.xml, update_xmlfile)
Exemplo n.º 2
0
 def do_rename(vm, new_name, uuid=None, fail_info=[]):
     # Change name in XML
     logging.info("Rename %s to %s.", vm.name, new_name)
     try:
         vm = VMXML.vm_rename(vm, new_name, uuid)  # give it a new uuid
     except LibvirtXMLError, detail:
         raise error.TestFail("Rename %s to %s failed:\n%s" % (vm.name, new_name, detail))
Exemplo n.º 3
0
 def agent_connected():
     """
     Callback function to check if agent channel connected.
     """
     ga_tgt = VMXML.new_from_dumpxml(vm_name).get_section_string(
         '/devices/channel/target')
     return 'state="connected"' in ga_tgt
def create_attach_xml(update_xmlfile, disk_type, target_bus,
                      target_dev, source_iso="", disk_mode=""):
    """
    Create a xml file to update a device.

    :param update_xmlfile : path/file to save device XML
    :param source_iso : disk's source backing file.
    :param disk_type: disk's device type: cdrom or floppy
    :param target_bus: disk's target bus
    :param target_dev: disk's target device name
    :param disk_mode: readonly or shareable
    """
    if source_iso:
        libvirt.create_local_disk("iso", source_iso)
    disk_class = VMXML.get_device_class('disk')
    disk = disk_class(type_name='file')
    # Static definition for comparison in check_attach()
    disk.device = disk_type
    disk.target = dict(bus=target_bus, dev=target_dev)
    if source_iso:
        disk.driver = dict(name='qemu')
        disk.source = disk.new_disk_source(attrs={'file': source_iso})
        if disk_mode == "readonly":
            disk.readonly = True
        if disk_mode == "shareable":
            disk.share = True
    disk.xmltreefile.write()
    shutil.copyfile(disk.xml, update_xmlfile)
Exemplo n.º 5
0
 def agent_connected():
     """
     Callback function to check if agent channel connected.
     """
     ga_tgt = VMXML.new_from_dumpxml(vm_name).get_section_string(
         '/devices/channel/target')
     return 'state="connected"' in ga_tgt
Exemplo n.º 6
0
def create_attach_xml(update_xmlfile, source_iso, target_bus, target_dev):
    """
    Create a xml file to update a device.

    :param update_xmlfile : path/file to save device XML
    :param source_iso : disk's source backing file.
    :param target_bus : disk's target bus
    :param target_dev : disk's target device name
    """
    try:
        _file = open(source_iso, 'wb')
        _file.seek((1024 * 1024) - 1)
        _file.write(str(0))
        _file.close()
    except IOError:
        raise error.TestFail("Create source_iso failed!")
    disk_class = VMXML.get_device_class('disk')
    disk = disk_class(type_name='file')
    # Static definition for comparison in check_attach()
    disk.device = 'cdrom'
    disk.driver = dict(name='file')
    disk.source = disk.new_disk_source(attrs={'file': source_iso})
    disk.target = dict(bus=target_bus, dev=target_dev)
    disk.readonly = True
    disk.xmltreefile.write()
    shutil.copyfile(disk.xml, update_xmlfile)
Exemplo n.º 7
0
def create_attach_xml(update_xmlfile, source_iso, disk_type, target_bus,
                      target_dev, disk_mode=""):
    """
    Create a xml file to update a device.

    :param update_xmlfile : path/file to save device XML
    :param source_iso : disk's source backing file.
    :param disk_type: disk's device type: cdrom or floppy
    :param target_bus: disk's target bus
    :param target_dev: disk's target device name
    :param disk_mode: readonly or shareable
    """
    try:
        _file = open(source_iso, 'wb')
        _file.seek((1024 * 1024) - 1)
        _file.write(str(0))
        _file.close()
    except IOError:
        raise error.TestFail("Create source_iso failed!")
    disk_class = VMXML.get_device_class('disk')
    disk = disk_class(type_name='file')
    # Static definition for comparison in check_attach()
    disk.device = disk_type
    disk.driver = dict(name='qemu')
    disk.source = disk.new_disk_source(attrs={'file': source_iso})
    disk.target = dict(bus=target_bus, dev=target_dev)
    if disk_mode == "readonly":
        disk.readonly = True
    if disk_mode == "shareable":
        disk.share = True
    disk.xmltreefile.write()
    shutil.copyfile(disk.xml, update_xmlfile)
Exemplo n.º 8
0
 def do_rename(vm, new_name, uuid=None, fail_info=[]):
     # Change name in XML
     logging.info("Rename %s to %s.", vm.name, new_name)
     try:
         vm = VMXML.vm_rename(vm, new_name, uuid)  # give it a new uuid
     except LibvirtXMLError, detail:
         raise error.TestFail("Rename %s to %s failed:\n%s" %
                              (vm.name, new_name, detail))
Exemplo n.º 9
0
def create_attach_xml(params, test, update_xmlfile, source_iso, disk_type, target_bus,
                      target_dev, disk_mode="", disk_alias=None):
    """
    Create a xml file to update a device.

    :param parameters from cfg file
    :param update_xmlfile : path/file to save device XML
    :param source_iso : disk's source backing file.
    :param disk_type: disk's device type: cdrom or floppy
    :param target_bus: disk's target bus
    :param target_dev: disk's target device name
    :param disk_mode: readonly or shareable
    :param disk_alias: disk's alias name
    """
    slice_test = "yes" == params.get("disk_slice", "no")
    try:
        if slice_test:
            libvirt.create_local_disk("file", source_iso, size="1", disk_format="qcow2", extra="-o preallocation=full")
        else:
            with open(source_iso, 'wb') as _file:
                _file.seek((1024 * 1024) - 1)
                _file.write(str(0).encode())
    except IOError:
        test.fail("Create source_iso failed!")
    disk_class = VMXML.get_device_class('disk')
    disk = disk_class(type_name='file')
    # Static definition for comparison in check_attach()`
    disk.device = disk_type
    disk.driver = dict(name='qemu')
    disk_source = disk.new_disk_source(**{"attrs": {'file': source_iso}})
    # Add slice field involved in source
    if slice_test:
        slice_size_param = process.run("du -b %s" % source_iso).stdout_text.strip()
        slice_size = re.findall(r'[0-9]+', slice_size_param)
        slice_size = ''.join(slice_size)
        disk_source.slices = disk.new_slices(
                        **{"slice_type": "storage", "slice_offset": "0", "slice_size": slice_size})
    disk.source = disk_source
    disk.target = dict(bus=target_bus, dev=target_dev)
    if disk_mode == "readonly":
        disk.readonly = True
    if disk_mode == "shareable":
        disk.share = True
    if disk_alias:
        disk.alias = dict(name=disk_alias)
    disk.xmltreefile.write()
    shutil.copyfile(disk.xml, update_xmlfile)
Exemplo n.º 10
0
    def do_rename(vm, new_name, uuid=None, fail_info=[]):
        # Change name in XML
        logging.info("Rename %s to %s.", vm.name, new_name)
        try:
            vm = VMXML.vm_rename(vm, new_name, uuid)  # give it a new uuid
        except LibvirtXMLError as detail:
            test.fail("Rename %s to %s failed:\n%s" %
                      (vm.name, new_name, detail))

        # Exercize the defined XML
        try:
            vm.start()
        except virt_vm.VMStartError as detail:
            # Do not raise TestFail because vm should be restored
            fail_info.append("Start guest %s failed:%s" % (vm.name, detail))
        vm.destroy()
        return fail_info
Exemplo n.º 11
0
    def do_rename(vm, new_name, uuid=None, fail_info=[]):
        # Change name in XML
        logging.info("Rename %s to %s.", vm.name, new_name)
        try:
            vm = VMXML.vm_rename(vm, new_name, uuid)  # give it a new uuid
        except LibvirtXMLError as detail:
            test.fail("Rename %s to %s failed:\n%s"
                      % (vm.name, new_name, detail))

        # Exercize the defined XML
        try:
            vm.start()
        except virt_vm.VMStartError as detail:
            # Do not raise TestFail because vm should be restored
            fail_info.append("Start guest %s failed:%s" % (vm.name, detail))
        vm.destroy()
        return fail_info
Exemplo n.º 12
0
def create_attach_xml(test,
                      update_xmlfile,
                      source_iso,
                      disk_type,
                      target_bus,
                      target_dev,
                      disk_mode="",
                      disk_alias=None):
    """
    Create a xml file to update a device.

    :param update_xmlfile : path/file to save device XML
    :param source_iso : disk's source backing file.
    :param disk_type: disk's device type: cdrom or floppy
    :param target_bus: disk's target bus
    :param target_dev: disk's target device name
    :param disk_mode: readonly or shareable
    :param disk_alias: disk's alias name
    """
    try:
        with open(source_iso, 'wb') as _file:
            _file.seek((1024 * 1024) - 1)
            _file.write(str(0).encode())
    except IOError:
        test.fail("Create source_iso failed!")
    disk_class = VMXML.get_device_class('disk')
    disk = disk_class(type_name='file')
    # Static definition for comparison in check_attach()
    disk.device = disk_type
    disk.driver = dict(name='qemu')
    disk.source = disk.new_disk_source(attrs={'file': source_iso})
    disk.target = dict(bus=target_bus, dev=target_dev)
    if disk_mode == "readonly":
        disk.readonly = True
    if disk_mode == "shareable":
        disk.share = True
    if disk_alias:
        disk.alias = dict(name=disk_alias)
    disk.xmltreefile.write()
    shutil.copyfile(disk.xml, update_xmlfile)
Exemplo n.º 13
0
    def check_result(disk_source, disk_type, disk_target, flags, attach=True):
        """
        Check the test result of update-device command.
        """
        vm_state = pre_vm_state
        active_vmxml = VMXML.new_from_dumpxml(vm_name)
        active_attached = is_attached(active_vmxml.devices, disk_type,
                                      disk_source, disk_target)
        if vm_state != "transient":
            inactive_vmxml = VMXML.new_from_dumpxml(vm_name,
                                                    options="--inactive")
            inactive_attached = is_attached(inactive_vmxml.devices, disk_type,
                                            disk_source, disk_target)

        if flags.count("config") and not flags.count("live"):
            if vm_state != "transient":
                if attach:
                    if not inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML not updated"
                            " when --config options used for"
                            " attachment")
                    if vm_state != "shutoff":
                        if active_attached:
                            raise exceptions.TestFail(
                                "Active domain XML updated "
                                "when --config options used"
                                " for attachment")
                else:
                    if inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML not updated"
                            " when --config options used for"
                            " detachment")
                    if vm_state != "shutoff":
                        if not active_attached:
                            raise exceptions.TestFail(
                                "Active domain XML updated "
                                "when --config options used"
                                " for detachment")
        elif flags.count("live") and not flags.count("config"):
            if attach:
                if vm_state in ["paused", "running", "transient"]:
                    if not active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --live options used for"
                            " attachment")
                if vm_state in ["paused", "running"]:
                    if inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML updated "
                            "when --live options used for"
                            " attachment")
            else:
                if vm_state in ["paused", "running", "transient"]:
                    if active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --live options used for"
                            " detachment")
                if vm_state in ["paused", "running"]:
                    if not inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML updated "
                            "when --live options used for"
                            " detachment")
        elif flags.count("live") and flags.count("config"):
            if attach:
                if vm_state in ["paused", "running"]:
                    if not active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --live --config options"
                            " used for attachment")
                    if not inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML not updated"
                            " when --live --config options "
                            "used for attachment")
            else:
                if vm_state in ["paused", "running"]:
                    if active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --live --config options"
                            " used for detachment")
                    if inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML not updated"
                            " when --live --config options "
                            "used for detachment")
        elif flags.count("current") or flags == "":
            if attach:
                if vm_state in ["paused", "running", "transient"]:
                    if not active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated "
                            "when --current options used "
                            "for attachment")
                if vm_state in ["paused", "running"]:
                    if inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML updated "
                            "when --current options used "
                            "for live attachment")
                if vm_state == "shutoff" and not inactive_attached:
                    raise exceptions.TestFail(
                        "Inactive domain XML not updated "
                        "when --current options used for "
                        "attachment")
            else:
                if vm_state in ["paused", "running", "transient"]:
                    if active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --current options used "
                            "for detachment")
                if vm_state in ["paused", "running"]:
                    if not inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML updated "
                            "when --current options used "
                            "for live detachment")
                if vm_state == "shutoff" and inactive_attached:
                    raise exceptions.TestFail("Inactive domain XML not updated"
                                              " when --current options used "
                                              "for detachment")
Exemplo n.º 14
0
def run(test, params, env):
    """
    Test command: virsh update-device.

    Update device from an XML <file>.
    1.Prepare test environment, adding a cdrom/floppy to VM.
    2.Perform virsh update-device operation.
    3.Recover test environment.
    4.Confirm the test result.
    """

    # Before doing anything - let's be sure we can support this test
    # Parse flag list, skip testing early if flag is not supported
    # NOTE: "".split("--") returns [''] which messes up later empty test
    flag = params.get("updatedevice_flag", "")
    flag_list = []
    if flag.count("--"):
        flag_list = flag.split("--")
    for item in flag_list:
        option = item.strip()
        if option == "":
            continue
        if not bool(virsh.has_command_help_match("update-device", option)):
            raise error.TestNAError("virsh update-device doesn't support --%s"
                                    % option)

    # As per RH BZ 961443 avoid testing before behavior changes
    if 'config' in flag_list:
        # SKIP tests using --config if libvirt is 0.9.10 or earlier
        if not libvirt_version.version_compare(0, 9, 10):
            raise error.TestNAError("BZ 961443: --config behavior change "
                                    "in version 0.9.10")
    if 'persistent' in flag_list:
        # SKIP tests using --persistent if libvirt 1.0.5 or earlier
        if not libvirt_version.version_compare(1, 0, 5):
            raise error.TestNAError("BZ 961443: --persistent behavior change "
                                    "in version 1.0.5")

    # Prepare initial vm state
    vm_name = params.get("main_vm")
    vmxml = VMXML.new_from_dumpxml(vm_name, options="--inactive")
    vm = env.get_vm(vm_name)
    start_vm = "yes" == params.get("start_vm", "no")

    # Get the target bus/dev
    disk_type = params.get("disk_type", "cdrom")
    target_bus = params.get("updatedevice_target_bus", "ide")
    target_dev = params.get("updatedevice_target_dev", "hdc")
    disk_mode = params.get("disk_mode", "")
    support_mode = ['readonly', 'shareable']
    if not disk_mode and disk_mode not in support_mode:
        raise error.TestError("%s not in support mode %s"
                              % (disk_mode, support_mode))

    # Prepare tmp directory and files.
    orig_iso = os.path.join(test.virtdir, "orig.iso")
    test_iso = os.path.join(test.virtdir, "test.iso")
    test_diff_iso = os.path.join(test.virtdir, "test_diff.iso")
    update_xmlfile = os.path.join(test.tmpdir, "update.xml")
    create_attach_xml(update_xmlfile, test_iso, disk_type, target_bus,
                      target_dev, disk_mode)

    # This test needs a cdrom/floppy attached first - attach a cdrom/floppy
    # to a shutdown vm. Then decide to restart or not
    if vm.is_alive():
        vm.destroy(gracefully=False)
    # Vm should be in 'shut off' status
    utils_misc.wait_for(lambda: vm.state() == "shut off", 30)
    create_disk(vm_name, orig_iso, disk_type, target_dev, disk_mode)
    if start_vm:
        vm.start()
        vm.wait_for_login().close()
        domid = vm.get_id()
    else:
        domid = "domid invalid; domain is shut-off"

    # Get remaining parameters for configuration.
    twice = "yes" == params.get("updatedevice_twice", "no")
    diff_iso = "yes" == params.get("updatedevice_diff_iso", "no")
    vm_ref = params.get("updatedevice_vm_ref", "")
    status_error = "yes" == params.get("status_error", "no")
    extra = params.get("updatedevice_extra", "")

    # OK let's give this a whirl...
    errmsg = ""
    try:
        if vm_ref == "id":
            vm_ref = domid
            if twice:
                # Don't pass in any flags
                ret = virsh.update_device(domainarg=domid, filearg=update_xmlfile,
                                          ignore_status=True, debug=True)
                if not status_error:
                    status = ret.exit_status
                    errmsg += ret.stderr
                    libvirt.check_exit_status(ret)
            if diff_iso:
                # Swap filename of device backing file in update.xml
                os.remove(update_xmlfile)
                create_attach_xml(update_xmlfile, test_diff_iso, disk_type,
                                  target_bus, target_dev, disk_mode)
        elif vm_ref == "uuid":
            vm_ref = vmxml.uuid
        elif vm_ref == "hex_id":
            vm_ref = hex(int(domid))
        elif vm_ref.find("updatedevice_invalid") != -1:
            vm_ref = params.get(vm_ref)
        elif vm_ref == "name":
            vm_ref = "%s %s" % (vm_name, extra)

        cmdresult = virsh.update_device(domainarg=vm_ref,
                                        filearg=update_xmlfile,
                                        flagstr=flag,
                                        ignore_status=True,
                                        debug=True)
        status = cmdresult.exit_status
        if not status_error:
            errmsg += cmdresult.stderr

        active_vmxml = VMXML.new_from_dumpxml(vm_name)
        inactive_vmxml = VMXML.new_from_dumpxml(vm_name,
                                                options="--inactive")
    finally:
        vm.destroy(gracefully=False, free_mac_addresses=False)
        vmxml.undefine()
        vmxml.restore()
        vmxml.define()
        if os.path.exists(orig_iso):
            os.remove(orig_iso)
        if os.path.exists(test_iso):
            os.remove(test_iso)
        if os.path.exists(test_diff_iso):
            os.remove(test_diff_iso)

    # Result handling logic set errmsg only on error
    if status_error:
        if status == 0:
            errmsg += "\nRun successfully with wrong command!\n"
    else:  # Normal test
        if status != 0:
            errmsg += "\nRun failed with right command\n"
        if diff_iso:  # Expect the backing file to have updated
            active_attached = is_attached(active_vmxml.devices, disk_type,
                                          test_diff_iso, target_dev)
            inactive_attached = is_attached(inactive_vmxml.devices, disk_type,
                                            test_diff_iso, target_dev)
        else:  # Expect backing file to remain the same
            active_attached = is_attached(active_vmxml.devices, disk_type,
                                          test_iso, target_dev)
            inactive_attached = is_attached(inactive_vmxml.devices, disk_type,
                                            test_iso, target_dev)

        # Check behavior of combination before individual!
        if "config" in flag_list and "live" in flag_list:
            if not active_attached:
                errmsg += ("Active domain XML not updated when "
                           "--config --live options used\n")
            if not inactive_attached:
                errmsg += ("Inactive domain XML not updated when "
                           "--config --live options used\n")

        elif "live" in flag_list and inactive_attached:
            errmsg += ("Inactive domain XML updated when "
                       "--live option used\n")

        elif "config" in flag_list and active_attached:
            errmsg += ("Active domain XML updated when "
                       "--config option used\n")

        # persistent option behavior depends on start_vm
        if "persistent" in flag_list:
            if start_vm:
                if not active_attached or not inactive_attached:
                    errmsg += ("XML not updated when --persistent "
                               "option used on active domain\n")

            else:
                if not inactive_attached:
                    errmsg += ("XML not updated when --persistent "
                               "option used on inactive domain\n")
        if len(flag_list) == 0:
            # Not specifying any flag is the same as specifying --current
            if start_vm:
                if not active_attached:
                    errmsg += "Active domain XML not updated\n"
                elif inactive_attached:
                    errmsg += ("Inactive domain XML updated when active "
                               "requested\n")

    # Log some debugging info before destroying instances
    if errmsg and not status_error:
        logging.debug("Active XML:")
        logging.debug(str(active_vmxml))
        logging.debug("Inactive XML:")
        logging.debug(str(inactive_vmxml))
        logging.debug("active_attached: %s", str(active_attached))
        logging.debug("inctive_attached: %s", str(inactive_attached))
        logging.debug("Device XML:")
        logging.debug(open(update_xmlfile, "r").read())

    # clean up tmp files
    del vmxml
    del active_vmxml
    del inactive_vmxml
    os.unlink(update_xmlfile)

    if errmsg:
        raise error.TestFail(errmsg)
    def check_result(disk_source, disk_type, disk_target,
                     flags, attach=True):
        """
        Check the test result of update-device command.
        """
        vm_state = pre_vm_state
        active_vmxml = VMXML.new_from_dumpxml(vm_name)
        active_attached = is_attached(active_vmxml.devices, disk_type,
                                      disk_source, disk_target)
        if vm_state != "transient":
            inactive_vmxml = VMXML.new_from_dumpxml(vm_name,
                                                    options="--inactive")
            inactive_attached = is_attached(inactive_vmxml.devices, disk_type,
                                            disk_source, disk_target)

        if flags.count("config") and not flags.count("live"):
            if vm_state != "transient":
                if attach:
                    if not inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML not updated"
                                                  " when --config options used for"
                                                  " attachment")
                    if vm_state != "shutoff":
                        if active_attached:
                            raise exceptions.TestFail("Active domain XML updated "
                                                      "when --config options used"
                                                      " for attachment")
                else:
                    if inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML not updated"
                                                  " when --config options used for"
                                                  " detachment")
                    if vm_state != "shutoff":
                        if not active_attached:
                            raise exceptions.TestFail("Active domain XML updated "
                                                      "when --config options used"
                                                      " for detachment")
        elif flags.count("live") and not flags.count("config"):
            if attach:
                if vm_state in ["paused", "running", "transient"]:
                    if not active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --live options used for"
                                                  " attachment")
                if vm_state in ["paused", "running"]:
                    if inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML updated "
                                                  "when --live options used for"
                                                  " attachment")
            else:
                if vm_state in ["paused", "running", "transient"]:
                    if active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --live options used for"
                                                  " detachment")
                if vm_state in ["paused", "running"]:
                    if not inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML updated "
                                                  "when --live options used for"
                                                  " detachment")
        elif flags.count("live") and flags.count("config"):
            if attach:
                if vm_state in ["paused", "running"]:
                    if not active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --live --config options"
                                                  " used for attachment")
                    if not inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML not updated"
                                                  " when --live --config options "
                                                  "used for attachment")
            else:
                if vm_state in ["paused", "running"]:
                    if active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --live --config options"
                                                  " used for detachment")
                    if inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML not updated"
                                                  " when --live --config options "
                                                  "used for detachment")
        elif flags.count("current") or flags == "":
            if attach:
                if vm_state in ["paused", "running", "transient"]:
                    if not active_attached:
                        raise exceptions.TestFail("Active domain XML not updated "
                                                  "when --current options used "
                                                  "for attachment")
                if vm_state in ["paused", "running"]:
                    if inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML updated "
                                                  "when --current options used "
                                                  "for live attachment")
                if vm_state == "shutoff" and not inactive_attached:
                    raise exceptions.TestFail("Inactive domain XML not updated "
                                              "when --current options used for "
                                              "attachment")
            else:
                if vm_state in ["paused", "running", "transient"]:
                    if active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --current options used "
                                                  "for detachment")
                if vm_state in ["paused", "running"]:
                    if not inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML updated "
                                                  "when --current options used "
                                                  "for live detachment")
                if vm_state == "shutoff" and inactive_attached:
                    raise exceptions.TestFail("Inactive domain XML not updated"
                                              " when --current options used "
                                              "for detachment")
Exemplo n.º 16
0
def run(test, params, env):
    """
    Restart libvirtd and check the consistent of VM states.
    """

    def agent_connected():
        """
        Callback function to check if agent channel connected.
        """
        ga_tgt = VMXML.new_from_dumpxml(vm_name).get_section_string(
            '/devices/channel/target')
        return 'state="connected"' in ga_tgt

    vm_name = params.get('main_vm')
    vm = env.get_vm(vm_name)
    if vm.is_alive():
        vm.destroy()
        time.sleep(2)
        vm.start()
        time.sleep(20)

    # Wait guest agent channel to be connected to avoid XML differ
    try:
        if not utils_misc.wait_for(agent_connected, 30):
            logging.warning('Agent channel not connected')
    except LibvirtXMLNotFoundError:
        pass

    vm_xml = VMXML.new_from_dumpxml(vm_name)
    logging.debug(vm_xml)

    # Skip the test when serial login is not available
    try:
        session = vm.wait_for_serial_login(60)
    except remote.LoginError:
        raise error.TestNAError('Serial console might needed to be '
                                'configured before test.')
    # Send a command line without waiting result
    try:
        session.cmd('sleep 30; echo hello', timeout=0)
    except ShellTimeoutError:
        pass

    # Restart libvirtd
    utils_libvirtd.Libvirtd().restart()

    # Check whether guest is still working
    vm.cleanup_serial_console()
    vm.create_serial_console()
    try:
        vm.serial_console.read_until_any_line_matches(['hello'], timeout=60)
    except ExpectTimeoutError:
        raise error.TestFail('Timeout when waiting for command output. '
                             'Maybe your guest is refreshed.')

    # Wait guest agent channel to be reconnected to avoid XML differ
    try:
        if not utils_misc.wait_for(agent_connected, 30):
            logging.warning('Agent channel not recovered after libvirtd '
                            'restart')
    except LibvirtXMLNotFoundError:
        pass

    # Check whether domain XML changed
    vm_xml_new = VMXML.new_from_dumpxml(vm_name)
    if str(vm_xml) != str(vm_xml_new):
        diff_txt = '\n'.join(
            difflib.unified_diff(
                str(vm_xml).splitlines(),
                str(vm_xml_new).splitlines(),
                lineterm='',
            )
        )
        raise error.TestFail("XML changed after libvirtd restart:\n%s"
                             % diff_txt)
Exemplo n.º 17
0
def run(test, params, env):
    """
    Test command: virsh update-device.

    Update device from an XML <file>.
    1.Prepare test environment, adding a cdrom/floppy to VM.
    2.Perform virsh update-device operation.
    3.Recover test environment.
    4.Confirm the test result.
    """

    # Before doing anything - let's be sure we can support this test
    # Parse flag list, skip testing early if flag is not supported
    # NOTE: "".split("--") returns [''] which messes up later empty test
    flag = params.get("updatedevice_flag", "")
    flag_list = []
    if flag.count("--"):
        flag_list = flag.split("--")
    for item in flag_list:
        option = item.strip()
        if option == "":
            continue
        if not bool(virsh.has_command_help_match("update-device", option)):
            raise error.TestNAError(
                "virsh update-device doesn't support --%s" % option)

    # As per RH BZ 961443 avoid testing before behavior changes
    if 'config' in flag_list:
        # SKIP tests using --config if libvirt is 0.9.10 or earlier
        if not libvirt_version.version_compare(0, 9, 10):
            raise error.TestNAError("BZ 961443: --config behavior change "
                                    "in version 0.9.10")
    if 'persistent' in flag_list:
        # SKIP tests using --persistent if libvirt 1.0.5 or earlier
        if not libvirt_version.version_compare(1, 0, 5):
            raise error.TestNAError("BZ 961443: --persistent behavior change "
                                    "in version 1.0.5")

    # Prepare initial vm state
    vm_name = params.get("main_vm")
    vmxml = VMXML.new_from_dumpxml(vm_name, options="--inactive")
    vm = env.get_vm(vm_name)
    start_vm = "yes" == params.get("start_vm", "no")

    # Get the target bus/dev
    disk_type = params.get("disk_type", "cdrom")
    target_bus = params.get("updatedevice_target_bus", "ide")
    target_dev = params.get("updatedevice_target_dev", "hdc")
    disk_mode = params.get("disk_mode", "")
    support_mode = ['readonly', 'shareable']
    if not disk_mode and disk_mode not in support_mode:
        raise error.TestError("%s not in support mode %s" %
                              (disk_mode, support_mode))

    # Prepare tmp directory and files.
    orig_iso = os.path.join(test.virtdir, "orig.iso")
    test_iso = os.path.join(test.virtdir, "test.iso")
    test_diff_iso = os.path.join(test.virtdir, "test_diff.iso")
    update_xmlfile = os.path.join(test.tmpdir, "update.xml")
    create_attach_xml(update_xmlfile, test_iso, disk_type, target_bus,
                      target_dev, disk_mode)

    # This test needs a cdrom/floppy attached first - attach a cdrom/floppy
    # to a shutdown vm. Then decide to restart or not
    if vm.is_alive():
        vm.destroy()
    create_disk(vm_name, orig_iso, disk_type, target_dev, disk_mode)
    if start_vm:
        vm.start()
        domid = vm.get_id()
    else:
        domid = "domid invalid; domain is shut-off"

    # Get remaining parameters for configuration.
    twice = "yes" == params.get("updatedevice_twice", "no")
    diff_iso = "yes" == params.get("updatedevice_diff_iso", "no")
    vm_ref = params.get("updatedevice_vm_ref", "")
    status_error = "yes" == params.get("status_error", "no")
    extra = params.get("updatedevice_extra", "")

    # OK let's give this a whirl...
    try:
        if vm_ref == "id":
            vm_ref = domid
            if twice:
                # Don't pass in any flags
                virsh.update_device(domainarg=domid,
                                    filearg=update_xmlfile,
                                    ignore_status=True,
                                    debug=True)
            if diff_iso:
                # Swap filename of device backing file in update.xml
                os.remove(update_xmlfile)
                create_attach_xml(update_xmlfile, test_diff_iso, disk_type,
                                  target_bus, target_dev, disk_mode)
        elif vm_ref == "uuid":
            vm_ref = vmxml.uuid
        elif vm_ref == "hex_id":
            vm_ref = hex(int(domid))
        elif vm_ref.find("updatedevice_invalid") != -1:
            vm_ref = params.get(vm_ref)
        elif vm_ref == "name":
            vm_ref = "%s %s" % (vm_name, extra)

        cmdresult = virsh.update_device(domainarg=vm_ref,
                                        filearg=update_xmlfile,
                                        flagstr=flag,
                                        ignore_status=True,
                                        debug=True)
        status = cmdresult.exit_status

        active_vmxml = VMXML.new_from_dumpxml(vm_name)
        inactive_vmxml = VMXML.new_from_dumpxml(vm_name, options="--inactive")
    finally:
        vm.destroy(gracefully=False, free_mac_addresses=False)
        vmxml.undefine()
        vmxml.restore()
        vmxml.define()
        if os.path.exists(orig_iso):
            os.remove(orig_iso)
        if os.path.exists(test_iso):
            os.remove(test_iso)
        if os.path.exists(test_diff_iso):
            os.remove(test_diff_iso)

    # Result handling logic set errmsg only on error
    errmsg = None
    if status_error:
        if status == 0:
            errmsg = "Run successfully with wrong command!"
    else:  # Normal test
        if status != 0:
            errmsg = "Run failed with right command"
        if diff_iso:  # Expect the backing file to have updated
            active_attached = is_attached(active_vmxml.devices, disk_type,
                                          test_diff_iso, target_dev)
            inactive_attached = is_attached(inactive_vmxml.devices, disk_type,
                                            test_diff_iso, target_dev)
        else:  # Expect backing file to remain the same
            active_attached = is_attached(active_vmxml.devices, disk_type,
                                          test_iso, target_dev)
            inactive_attached = is_attached(inactive_vmxml.devices, disk_type,
                                            test_iso, target_dev)

        # Check behavior of combination before individual!
        if "config" in flag_list and "live" in flag_list:
            if not active_attached:
                errmsg = ("Active domain XML not updated when "
                          "--config --live options used")
            if not inactive_attached:
                errmsg = ("Inactive domain XML not updated when "
                          "--config --live options used")

        elif "live" in flag_list and inactive_attached:
            errmsg = ("Inactive domain XML updated when " "--live option used")

        elif "config" in flag_list and active_attached:
            errmsg = ("Active domain XML updated when " "--config option used")

        # persistent option behavior depends on start_vm
        if "persistent" in flag_list:
            if start_vm:
                if not active_attached or not inactive_attached:
                    errmsg = ("XML not updated when --persistent "
                              "option used on active domain")

            else:
                if not inactive_attached:
                    errmsg = ("XML not updated when --persistent "
                              "option used on inactive domain")
        if len(flag_list) == 0:
            # Not specifying any flag is the same as specifying --current
            if start_vm:
                if not active_attached:
                    errmsg = "Active domain XML not updated"
                elif inactive_attached:
                    errmsg = ("Inactive domain XML updated when active "
                              "requested")

    # Log some debugging info before destroying instances
    if errmsg is not None:
        logging.debug("Active XML:")
        logging.debug(str(active_vmxml))
        logging.debug("Inactive XML:")
        logging.debug(str(inactive_vmxml))
        logging.debug("active_attached: %s", str(active_attached))
        logging.debug("inctive_attached: %s", str(inactive_attached))
        logging.debug("Device XML:")
        logging.debug(open(update_xmlfile, "r").read())

    # clean up tmp files
    del vmxml
    del active_vmxml
    del inactive_vmxml
    os.unlink(update_xmlfile)

    if errmsg is not None:
        raise error.TestFail(errmsg)
def run(test, params, env):
    """
    Test command: virsh update-device.

    Update device from an XML <file>.
    1.Prepare test environment, adding a cdrom/floppy to VM.
    2.Perform virsh update-device operation.
    3.Recover test environment.
    4.Confirm the test result.
    """

    vm_name = params.get("main_vm")
    vm = env.get_vm(vm_name)
    pre_vm_state = params.get("at_dt_device_pre_vm_state")
    virsh_dargs = {"debug": True, "ignore_status": True}

    def is_attached(vmxml_devices, disk_type, source_file, target_dev):
        """
        Check attached device and disk exist or not.

        :param vmxml_devices: VMXMLDevices instance
        :param disk_type: disk's device type: cdrom or floppy
        :param source_file : disk's source file to check
        :param target_dev : target device name
        :return: True/False if backing file and device found
        """
        disks = vmxml_devices.by_device_tag('disk')
        for disk in disks:
            logging.debug("Check disk XML:\n%s", open(disk['xml']).read())
            if disk.device != disk_type:
                continue
            if disk.target['dev'] != target_dev:
                continue
            if disk.xmltreefile.find('source') is not None:
                if disk.source.attrs['file'] != source_file:
                    continue
            else:
                continue
            # All three conditions met
            logging.debug("Find %s in given disk XML", source_file)
            return True
        logging.debug("Not find %s in gievn disk XML", source_file)
        return False

    def check_result(disk_source, disk_type, disk_target,
                     flags, attach=True):
        """
        Check the test result of update-device command.
        """
        vm_state = pre_vm_state
        active_vmxml = VMXML.new_from_dumpxml(vm_name)
        active_attached = is_attached(active_vmxml.devices, disk_type,
                                      disk_source, disk_target)
        if vm_state != "transient":
            inactive_vmxml = VMXML.new_from_dumpxml(vm_name,
                                                    options="--inactive")
            inactive_attached = is_attached(inactive_vmxml.devices, disk_type,
                                            disk_source, disk_target)

        if flags.count("config") and not flags.count("live"):
            if vm_state != "transient":
                if attach:
                    if not inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML not updated"
                                                  " when --config options used for"
                                                  " attachment")
                    if vm_state != "shutoff":
                        if active_attached:
                            raise exceptions.TestFail("Active domain XML updated "
                                                      "when --config options used"
                                                      " for attachment")
                else:
                    if inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML not updated"
                                                  " when --config options used for"
                                                  " detachment")
                    if vm_state != "shutoff":
                        if not active_attached:
                            raise exceptions.TestFail("Active domain XML updated "
                                                      "when --config options used"
                                                      " for detachment")
        elif flags.count("live") and not flags.count("config"):
            if attach:
                if vm_state in ["paused", "running", "transient"]:
                    if not active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --live options used for"
                                                  " attachment")
                if vm_state in ["paused", "running"]:
                    if inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML updated "
                                                  "when --live options used for"
                                                  " attachment")
            else:
                if vm_state in ["paused", "running", "transient"]:
                    if active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --live options used for"
                                                  " detachment")
                if vm_state in ["paused", "running"]:
                    if not inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML updated "
                                                  "when --live options used for"
                                                  " detachment")
        elif flags.count("live") and flags.count("config"):
            if attach:
                if vm_state in ["paused", "running"]:
                    if not active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --live --config options"
                                                  " used for attachment")
                    if not inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML not updated"
                                                  " when --live --config options "
                                                  "used for attachment")
            else:
                if vm_state in ["paused", "running"]:
                    if active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --live --config options"
                                                  " used for detachment")
                    if inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML not updated"
                                                  " when --live --config options "
                                                  "used for detachment")
        elif flags.count("current") or flags == "":
            if attach:
                if vm_state in ["paused", "running", "transient"]:
                    if not active_attached:
                        raise exceptions.TestFail("Active domain XML not updated "
                                                  "when --current options used "
                                                  "for attachment")
                if vm_state in ["paused", "running"]:
                    if inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML updated "
                                                  "when --current options used "
                                                  "for live attachment")
                if vm_state == "shutoff" and not inactive_attached:
                    raise exceptions.TestFail("Inactive domain XML not updated "
                                              "when --current options used for "
                                              "attachment")
            else:
                if vm_state in ["paused", "running", "transient"]:
                    if active_attached:
                        raise exceptions.TestFail("Active domain XML not updated"
                                                  " when --current options used "
                                                  "for detachment")
                if vm_state in ["paused", "running"]:
                    if not inactive_attached:
                        raise exceptions.TestFail("Inactive domain XML updated "
                                                  "when --current options used "
                                                  "for live detachment")
                if vm_state == "shutoff" and inactive_attached:
                    raise exceptions.TestFail("Inactive domain XML not updated"
                                              " when --current options used "
                                              "for detachment")

    def check_rhel_version(release_ver, session=None):
        """
        Login to guest and check its release version
        """
        rhel_release = {"rhel6": "Red Hat Enterprise Linux Server release 6",
                        "rhel7": "Red Hat Enterprise Linux Server release 7",
                        "fedora": "Fedora release"}
        version_file = "/etc/redhat-release"
        if not rhel_release.has_key(release_ver):
            logging.error("Can't support this version of guest: %s",
                          release_ver)
            return False

        cmd = "grep '%s' %s" % (rhel_release[release_ver], version_file)
        if session:
            s = session.cmd_status(cmd)
        else:
            s = process.run(cmd, ignore_status=True, shell=True).exit_status

        logging.debug("Check version cmd return:%s", s)
        if s == 0:
            return True
        else:
            return False

    vmxml_backup = VMXML.new_from_dumpxml(vm_name, options="--inactive")
    # Before doing anything - let's be sure we can support this test
    # Parse flag list, skip testing early if flag is not supported
    # NOTE: "".split("--") returns [''] which messes up later empty test
    at_flag = params.get("at_dt_device_at_options", "")
    dt_flag = params.get("at_dt_device_dt_options", "")
    flag_list = []
    if at_flag.count("--"):
        flag_list.extend(at_flag.split("--"))
    if dt_flag.count("--"):
        flag_list.extend(dt_flag.split("--"))
    for item in flag_list:
        option = item.strip()
        if option == "":
            continue
        if not bool(virsh.has_command_help_match("update-device", option)):
            raise exceptions.TestSkipError("virsh update-device doesn't support "
                                           "--%s" % option)

    # As per RH BZ 961443 avoid testing before behavior changes
    if 'config' in flag_list:
        # SKIP tests using --config if libvirt is 0.9.10 or earlier
        if not libvirt_version.version_compare(0, 9, 10):
            raise exceptions.TestSkipError("BZ 961443: --config behavior change "
                                           "in version 0.9.10")
    if 'persistent' in flag_list or 'live' in flag_list:
        # SKIP tests using --persistent if libvirt 1.0.5 or earlier
        if not libvirt_version.version_compare(1, 0, 5):
            raise exceptions.TestSkipError("BZ 961443: --persistent behavior "
                                           "change in version 1.0.5")

    # Get the target bus/dev
    disk_type = params.get("disk_type", "cdrom")
    target_bus = params.get("updatedevice_target_bus", "ide")
    target_dev = params.get("updatedevice_target_dev", "hdc")
    disk_mode = params.get("disk_mode", "")
    support_mode = ['readonly', 'shareable']
    if not disk_mode and disk_mode not in support_mode:
        raise exceptions.TestError("%s not in support mode %s"
                                   % (disk_mode, support_mode))

    # Prepare tmp directory and files.
    orig_iso = os.path.join(data_dir.get_tmp_dir(), "orig.iso")
    test_iso = os.path.join(data_dir.get_tmp_dir(), "test.iso")

    # Check the version first.
    host_rhel6 = check_rhel_version('rhel6')
    guest_rhel6 = False
    if not vm.is_alive():
        vm.start()
    session = vm.wait_for_login()
    if check_rhel_version('rhel6', session):
        guest_rhel6 = True
    session.close()
    vm.destroy(gracefully=False)

    try:
        # Prepare the disk first.
        create_disk(vm_name, orig_iso, disk_type, target_dev, disk_mode)
        vmxml_for_test = VMXML.new_from_dumpxml(vm_name,
                                                options="--inactive")

        # Turn VM into certain state.
        if pre_vm_state == "running":
            if at_flag == "--config" or dt_flag == "--config":
                if host_rhel6:
                    raise exceptions.TestSkipError("Config option not supported"
                                                   " on this host")
            logging.info("Starting %s..." % vm_name)
            if vm.is_dead():
                vm.start()
                vm.wait_for_login().close()
        elif pre_vm_state == "shutoff":
            if not at_flag or not dt_flag:
                if host_rhel6:
                    raise exceptions.TestSkipError("Default option not supported"
                                                   " on this host")
            logging.info("Shuting down %s..." % vm_name)
            if vm.is_alive():
                vm.destroy(gracefully=False)
        elif pre_vm_state == "paused":
            if at_flag == "--config" or dt_flag == "--config":
                if host_rhel6:
                    raise exceptions.TestSkipError("Config option not supported"
                                                   " on this host")
            logging.info("Pausing %s..." % vm_name)
            if vm.is_dead():
                vm.start()
                vm.wait_for_login().close()
            if not vm.pause():
                raise exceptions.TestSkipError("Cann't pause the domain")
        elif pre_vm_state == "transient":
            logging.info("Creating %s..." % vm_name)
            vm.undefine()
            if virsh.create(vmxml_for_test.xml, **virsh_dargs).exit_status:
                vmxml_backup.define()
                raise exceptions.TestSkipError("Cann't create the domain")
            vm.wait_for_login().close()
    except Exception, e:
        logging.error(str(e))
        if os.path.exists(orig_iso):
            os.remove(orig_iso)
        vmxml_backup.sync()
        raise exceptions.TestSkipError(str(e))
Exemplo n.º 19
0
def run(test, params, env):
    """
    Restart libvirtd and check the consistent of VM states.
    """
    def agent_connected():
        """
        Callback function to check if agent channel connected.
        """
        ga_tgt = VMXML.new_from_dumpxml(vm_name).get_section_string(
            '/devices/channel/target')
        return 'state="connected"' in ga_tgt

    vm_name = params.get('main_vm')
    vm = env.get_vm(vm_name)
    username = params.get("username")
    password = params.get("password")

    # Wait guest agent channel to be connected to avoid XML differ
    try:
        if not utils_misc.wait_for(agent_connected, 30):
            logging.warning('Agent channel not connected')
    except LibvirtXMLNotFoundError:
        pass

    vm_xml = VMXML.new_from_dumpxml(vm_name)
    logging.debug(vm_xml)

    # Skip the test when serial login is not available
    try:
        session = vm.wait_for_serial_login(60,
                                           username=username,
                                           password=password)
    except remote.LoginError:
        test.cancel('Serial console might needed to be '
                    'configured before test.')
    # Send a command line without waiting result
    try:
        session.cmd('sleep 30; echo hello', timeout=0)
    except ShellTimeoutError:
        pass

    # Restart libvirtd
    utils_libvirtd.Libvirtd().restart()

    # Check whether guest is still working
    vm.cleanup_serial_console()
    vm.create_serial_console()
    try:
        vm.serial_console.read_until_any_line_matches(['hello'], timeout=60)
    except ExpectTimeoutError:
        test.fail('Timeout when waiting for command output. '
                  'Maybe your guest is refreshed.')

    # Wait guest agent channel to be reconnected to avoid XML differ
    try:
        if not utils_misc.wait_for(agent_connected, 30):
            logging.warning('Agent channel not recovered after libvirtd '
                            'restart')
    except LibvirtXMLNotFoundError:
        pass

    # Check whether domain XML changed
    vm_xml_new = VMXML.new_from_dumpxml(vm_name)
    if str(vm_xml) != str(vm_xml_new):
        diff_txt = '\n'.join(
            difflib.unified_diff(
                str(vm_xml).splitlines(),
                str(vm_xml_new).splitlines(),
                lineterm='',
            ))
        test.fail("XML changed after libvirtd restart:\n%s" % diff_txt)
Exemplo n.º 20
0
def run(test, params, env):
    """
    Test command: virsh update-device.

    Update device from an XML <file>.
    1.Prepare test environment, adding a cdrom/floppy to VM.
    2.Perform virsh update-device operation.
    3.Recover test environment.
    4.Confirm the test result.
    """

    vm_name = params.get("main_vm")
    vm = env.get_vm(vm_name)
    pre_vm_state = params.get("at_dt_device_pre_vm_state")
    virsh_dargs = {"debug": True, "ignore_status": True}

    def is_attached(vmxml_devices, disk_type, source_file, target_dev):
        """
        Check attached device and disk exist or not.

        :param vmxml_devices: VMXMLDevices instance
        :param disk_type: disk's device type: cdrom or floppy
        :param source_file : disk's source file to check
        :param target_dev : target device name
        :return: True/False if backing file and device found
        """
        disks = vmxml_devices.by_device_tag('disk')
        for disk in disks:
            logging.debug("Check disk XML:\n%s", open(disk['xml']).read())
            if disk.device != disk_type:
                continue
            if disk.target['dev'] != target_dev:
                continue
            if disk.xmltreefile.find('source') is not None and \
                    'file' in disk.source.attrs:
                if disk.source.attrs['file'] != source_file:
                    continue
            else:
                continue
            # All three conditions met
            logging.debug("Find %s in given disk XML", source_file)
            return True
        logging.debug("Not find %s in gievn disk XML", source_file)
        return False

    def check_result(disk_source, disk_type, disk_target, flags, attach=True):
        """
        Check the test result of update-device command.
        """
        vm_state = pre_vm_state
        active_vmxml = VMXML.new_from_dumpxml(vm_name)
        active_attached = is_attached(active_vmxml.devices, disk_type,
                                      disk_source, disk_target)
        if vm_state != "transient":
            inactive_vmxml = VMXML.new_from_dumpxml(vm_name,
                                                    options="--inactive")
            inactive_attached = is_attached(inactive_vmxml.devices, disk_type,
                                            disk_source, disk_target)

        if flags.count("config") and not flags.count("live"):
            if vm_state != "transient":
                if attach:
                    if not inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML not updated"
                            " when --config options used for"
                            " attachment")
                    if vm_state != "shutoff":
                        if active_attached:
                            raise exceptions.TestFail(
                                "Active domain XML updated "
                                "when --config options used"
                                " for attachment")
                else:
                    if inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML not updated"
                            " when --config options used for"
                            " detachment")
                    if vm_state != "shutoff":
                        if not active_attached:
                            raise exceptions.TestFail(
                                "Active domain XML updated "
                                "when --config options used"
                                " for detachment")
        elif flags.count("live") and not flags.count("config"):
            if attach:
                if vm_state in ["paused", "running", "transient"]:
                    if not active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --live options used for"
                            " attachment")
                if vm_state in ["paused", "running"]:
                    if inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML updated "
                            "when --live options used for"
                            " attachment")
            else:
                if vm_state in ["paused", "running", "transient"]:
                    if active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --live options used for"
                            " detachment")
                if vm_state in ["paused", "running"]:
                    if not inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML updated "
                            "when --live options used for"
                            " detachment")
        elif flags.count("live") and flags.count("config"):
            if attach:
                if vm_state in ["paused", "running"]:
                    if not active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --live --config options"
                            " used for attachment")
                    if not inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML not updated"
                            " when --live --config options "
                            "used for attachment")
            else:
                if vm_state in ["paused", "running"]:
                    if active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --live --config options"
                            " used for detachment")
                    if inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML not updated"
                            " when --live --config options "
                            "used for detachment")
        elif flags.count("current") or flags == "":
            if attach:
                if vm_state in ["paused", "running", "transient"]:
                    if not active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated "
                            "when --current options used "
                            "for attachment")
                if vm_state in ["paused", "running"]:
                    if inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML updated "
                            "when --current options used "
                            "for live attachment")
                if vm_state == "shutoff" and not inactive_attached:
                    raise exceptions.TestFail(
                        "Inactive domain XML not updated "
                        "when --current options used for "
                        "attachment")
            else:
                if vm_state in ["paused", "running", "transient"]:
                    if active_attached:
                        raise exceptions.TestFail(
                            "Active domain XML not updated"
                            " when --current options used "
                            "for detachment")
                if vm_state in ["paused", "running"]:
                    if not inactive_attached:
                        raise exceptions.TestFail(
                            "Inactive domain XML updated "
                            "when --current options used "
                            "for live detachment")
                if vm_state == "shutoff" and inactive_attached:
                    raise exceptions.TestFail("Inactive domain XML not updated"
                                              " when --current options used "
                                              "for detachment")

    def check_rhel_version(release_ver, session=None):
        """
        Login to guest and check its release version
        """
        rhel_release = {
            "rhel6": "Red Hat Enterprise Linux Server release 6",
            "rhel7": "Red Hat Enterprise Linux Server release 7",
            "fedora": "Fedora release"
        }
        version_file = "/etc/redhat-release"
        if release_ver not in rhel_release:
            logging.error("Can't support this version of guest: %s",
                          release_ver)
            return False

        cmd = "grep '%s' %s" % (rhel_release[release_ver], version_file)
        if session:
            s = session.cmd_status(cmd)
        else:
            s = process.run(cmd, ignore_status=True, shell=True).exit_status

        logging.debug("Check version cmd return:%s", s)
        if s == 0:
            return True
        else:
            return False

    vmxml_backup = VMXML.new_from_dumpxml(vm_name, options="--inactive")
    # Before doing anything - let's be sure we can support this test
    # Parse flag list, skip testing early if flag is not supported
    # NOTE: "".split("--") returns [''] which messes up later empty test
    at_flag = params.get("at_dt_device_at_options", "")
    dt_flag = params.get("at_dt_device_dt_options", "")
    flag_list = []
    if at_flag.count("--"):
        flag_list.extend(at_flag.split("--"))
    if dt_flag.count("--"):
        flag_list.extend(dt_flag.split("--"))
    for item in flag_list:
        option = item.strip()
        if option == "":
            continue
        if not bool(virsh.has_command_help_match("update-device", option)):
            raise exceptions.TestSkipError(
                "virsh update-device doesn't support "
                "--%s" % option)

    # As per RH BZ 961443 avoid testing before behavior changes
    if 'config' in flag_list:
        # SKIP tests using --config if libvirt is 0.9.10 or earlier
        if not libvirt_version.version_compare(0, 9, 10):
            raise exceptions.TestSkipError(
                "BZ 961443: --config behavior change "
                "in version 0.9.10")
    if 'persistent' in flag_list or 'live' in flag_list:
        # SKIP tests using --persistent if libvirt 1.0.5 or earlier
        if not libvirt_version.version_compare(1, 0, 5):
            raise exceptions.TestSkipError("BZ 961443: --persistent behavior "
                                           "change in version 1.0.5")

    # Get the target bus/dev
    disk_type = params.get("disk_type", "cdrom")
    target_bus = params.get("updatedevice_target_bus", "ide")
    target_dev = params.get("updatedevice_target_dev", "hdc")
    disk_mode = params.get("disk_mode", "")
    support_mode = ['readonly', 'shareable']
    if not disk_mode and disk_mode not in support_mode:
        raise exceptions.TestError("%s not in support mode %s" %
                                   (disk_mode, support_mode))

    # Prepare tmp directory and files.
    orig_iso = os.path.join(data_dir.get_tmp_dir(), "orig.iso")
    test_iso = os.path.join(data_dir.get_tmp_dir(), "test.iso")

    # Check the version first.
    host_rhel6 = False
    guest_rhel6 = False
    if not params.get("skip_release_check", "no") == "yes":
        host_rhel6 = check_rhel_version('rhel6')
        if not vm.is_alive():
            vm.start()
        session = vm.wait_for_login()
        if check_rhel_version('rhel6', session):
            guest_rhel6 = True
        session.close()
    vm.destroy(gracefully=False)

    try:
        # Prepare the disk first.
        create_disk(vm_name, orig_iso, disk_type, target_dev, disk_mode)
        vmxml_for_test = VMXML.new_from_dumpxml(vm_name, options="--inactive")

        # Turn VM into certain state.
        if pre_vm_state == "running":
            if at_flag == "--config" or dt_flag == "--config":
                if host_rhel6:
                    raise exceptions.TestSkipError(
                        "Config option not supported"
                        " on this host")
            logging.info("Starting %s..." % vm_name)
            if vm.is_dead():
                vm.start()
                vm.wait_for_login().close()
        elif pre_vm_state == "shutoff":
            if not at_flag or not dt_flag:
                if host_rhel6:
                    raise exceptions.TestSkipError(
                        "Default option not supported"
                        " on this host")
            logging.info("Shuting down %s..." % vm_name)
            if vm.is_alive():
                vm.destroy(gracefully=False)
        elif pre_vm_state == "paused":
            if at_flag == "--config" or dt_flag == "--config":
                if host_rhel6:
                    raise exceptions.TestSkipError(
                        "Config option not supported"
                        " on this host")
            logging.info("Pausing %s..." % vm_name)
            if vm.is_dead():
                vm.start()
                vm.wait_for_login().close()
            if not vm.pause():
                raise exceptions.TestSkipError("Cann't pause the domain")
        elif pre_vm_state == "transient":
            logging.info("Creating %s..." % vm_name)
            vm.undefine()
            if virsh.create(vmxml_for_test.xml, **virsh_dargs).exit_status:
                vmxml_backup.define()
                raise exceptions.TestSkipError("Cann't create the domain")
            vm.wait_for_login().close()
    except Exception as e:
        logging.error(str(e))
        if os.path.exists(orig_iso):
            os.remove(orig_iso)
        vmxml_backup.sync()
        raise exceptions.TestSkipError(str(e))

    # Get remaining parameters for configuration.
    vm_ref = params.get("updatedevice_vm_ref", "domname")
    at_status_error = "yes" == params.get("at_status_error", "no")
    dt_status_error = "yes" == params.get("dt_status_error", "no")

    dom_uuid = vm.get_uuid()
    dom_id = vm.get_id()
    # Set domain reference.
    if vm_ref == "domname":
        vm_ref = vm_name
    elif vm_ref == "domid":
        vm_ref = dom_id
    elif vm_ref == "domuuid":
        vm_ref = dom_uuid
    elif vm_ref == "hexdomid" and dom_id is not None:
        vm_ref = hex(int(dom_id))

    try:
        # Get disk alias
        disk_alias = libvirt.get_disk_alias(vm, orig_iso)

        # Firstly detach the disk.
        update_xmlfile = os.path.join(data_dir.get_tmp_dir(), "update.xml")
        create_attach_xml(update_xmlfile, disk_type, target_bus, target_dev,
                          "", disk_mode, disk_alias)
        ret = virsh.update_device(vm_ref,
                                  filearg=update_xmlfile,
                                  flagstr=dt_flag,
                                  ignore_status=True,
                                  debug=True)
        if vm.is_paused():
            vm.resume()
            vm.wait_for_login().close()
        if vm.is_alive() and not guest_rhel6:
            time.sleep(5)
            # For rhel7 guest, need to update twice for it to take effect.
            ret = virsh.update_device(vm_ref,
                                      filearg=update_xmlfile,
                                      flagstr=dt_flag,
                                      ignore_status=True,
                                      debug=True)
        os.remove(update_xmlfile)
        libvirt.check_exit_status(ret, dt_status_error)
        if not ret.exit_status:
            check_result(orig_iso, disk_type, target_dev, dt_flag, False)

        # Then attach the disk.
        if pre_vm_state == "paused":
            if not vm.pause():
                raise exceptions.TestFail("Cann't pause the domain")
        create_attach_xml(update_xmlfile, disk_type, target_bus, target_dev,
                          test_iso, disk_mode, disk_alias)
        ret = virsh.update_device(vm_ref,
                                  filearg=update_xmlfile,
                                  flagstr=at_flag,
                                  ignore_status=True,
                                  debug=True)
        if vm.is_paused():
            vm.resume()
            vm.wait_for_login().close()
        update_twice = False
        if vm.is_alive() and not guest_rhel6:
            # For rhel7 guest, need to update twice for it to take effect.
            if (pre_vm_state in ["running", "paused"] and dt_flag == "--config"
                    and at_flag != "--config"):
                update_twice = True
            elif (pre_vm_state == "transient" and dt_flag.count("config")
                  and not at_flag.count("config")):
                update_twice = True
        if update_twice:
            time.sleep(5)
            ret = virsh.update_device(vm_ref,
                                      filearg=update_xmlfile,
                                      flagstr=at_flag,
                                      ignore_status=True,
                                      debug=True)
        libvirt.check_exit_status(ret, at_status_error)
        os.remove(update_xmlfile)
        if not ret.exit_status:
            check_result(test_iso, disk_type, target_dev, at_flag)
        # Try to start vm at last.
        if vm.is_dead():
            vm.start()
            vm.wait_for_login().close()

    finally:
        vm.destroy(gracefully=False, free_mac_addresses=False)
        vmxml_backup.sync()
        if os.path.exists(orig_iso):
            os.remove(orig_iso)
        if os.path.exists(test_iso):
            os.remove(test_iso)