On 07/04/2012 05:27 AM, tangchen wrote: > Hi Chris: > > I got all the comments, thanks. :) As you said, it is a really > complicate patch. Fortunately, most of the points are not big ones > because it won't raise problem for now. So if you don't mind, would > you please apply it first ? So that I don't need to do the whole > patch again.:) After that, I will send a much more simple patch to > fix all that you said. > > Thanks. :) >
Oh, sorry I wasn't clear. What you've said above is what I already did :) Your whole patchset All of this is now in the "next" branch. In case you missed the announcement- we're using this "next" branch for continuous-integration-testing. Basically all new code gets dumped there, and we have automated jobs running nightly to check for failures. Think of it like an automated autotest test :) It's to make sure all the changes we're putting in can play nice with each other. Every week or so, assuming there are no failures, LMR is using git cherry-pick to move patches into master. If you have time to fix the small things later, go for it. Otherwise I don't see them as critical, so don't worry about it :) > On 07/03/2012 10:04 PM, Chris Evich wrote: >> >> Cool, okay, taking a fresh look by trying to pretend I've never >> seen this code before... >> >> On 06/29/2012 03:56 AM, tangchen wrote: >>> Signed-off-by: Tang Chen<tanc...@cn.fujitsu.com> --- >>> client/tests/libvirt/tests/virsh_migrate.py | 267 >>> ++++++++++++++++++++++----- 1 files changed, 223 insertions(+), >>> 44 deletions(-) >>> >>> diff --git a/client/tests/libvirt/tests/virsh_migrate.py >>> b/client/tests/libvirt/tests/virsh_migrate.py index >>> b342987..16fd298 100644 --- >>> a/client/tests/libvirt/tests/virsh_migrate.py +++ >>> b/client/tests/libvirt/tests/virsh_migrate.py @@ -1,5 +1,6 @@ >>> -import logging, time -from autotest.client.shared import error >>> +import logging, os, re, time, shutil, codecs +from >>> autotest.client.shared import utils, error +from >>> autotest.client.virt import libvirt_vm, virt_utils, >>> virt_test_utils >>> >>> def run_virsh_migrate(test, params, env): """ @@ -16,51 +17,69 @@ >>> def run_virsh_migrate(test, params, env): else: return False >>> >>> - def cleanup_dest(vm, src_uri = ""): + def >>> cleanup_dest(vm, src_uri=""): >> >> Good, better style. >> >>> """ Clean up the destination host environment when doing the >>> uni-direction migration. """ - vm_state = vm.state() - >>> if vm_state == "running": - vm.destroy() - elif >>> vm_state == "paused": - vm.resume() - >>> vm.destroy() + logging.info("Cleaning up VMs on %s" % >>> vm.connect_uri) + try: + if >>> libvirt_vm.virsh_domain_exists(vm.name, vm.connect_uri): + >>> vm_state = vm.state() + if vm_state == "paused": + >>> vm.resume() + elif vm_state == "shut off": + >>> vm.start() + vm.destroy() + + if >>> vm.is_persistent(): + vm.undefine() >>> >>> - if vm.is_persistent(): - vm.undefine() + >>> except Exception, detail: + logging.error("Cleaning up >>> destination failed.\n%s" % detail) >>> >>> - vm.connect_uri = src_uri + if src_uri: + >>> vm.connect_uri = src_uri >> >> >> Okay, looking at this fresh, I like the new way. I was concerned >> for a moment throwing exception but not raising another would cause >> problem. However, assuming cleanup_dest() is only even done for >> uni-directional testing, I think it's okay. If there's a problem, >> the next attempt to migrate should fail, and we'll have logs to see >> what happened. Good. >> >>> >>> - def do_migration(dly, vm, dest_uri, options, extra): - >>> logging.info("Sleeping %d seconds before migration" % dly) - >>> time.sleep(dly) + def do_migration(delay, vm, dest_uri, >>> options, extra): + logging.info("Sleeping %d seconds >>> before migration" % delay) + time.sleep(delay) # Migrate >>> the guest. - successful = vm.migrate(dest_uri, options, >>> extra) - if not successful: - raise >>> error.TestFail("Migration failed for %s." % vm_name) + >>> successful = vm.migrate(dest_uri, options, extra, True, >>> True).exit_status + logging.info("successful: %d", >>> successful) + if int(successful) != 0: + >>> logging.error("Migration failed for %s." % vm_name) + >>> return False + + if options.count("dname") or >>> extra.count("dname"): + vm.name = >>> extra.split()[1].strip() >>> >> >> I'm sorry if I recommended this, I think I suggested a mistake :S >> This will only work if --dname is always the first option/value. >> However, I'm inclined to accept it since all the test >> configurations are setup this way. Something we can examine >> further later, let's not worry about it for now. >> >>> if vm.is_alive(): # vm.connect_uri was updated >>> logging.info("Alive guest found on destination %s." % dest_uri) >>> else: - raise error.TestFail("VM not running on >>> destination %s" % dest_uri) - - # Migration may fail, but >>> VM is alive on destination. - dest_state = >>> params.get("virsh_migrate_dest_state") - ret = >>> check_vm_state(vm, dest_state) - logging.info("Supposed >>> state: %s" % dest_state) - logging.info("Actual state: %s" >>> % vm.state()) - if not ret: - raise >>> error.TestFail("VM is not in the supposed state.") + >>> logging.error("VM not alive on destination %s" % dest_uri) + >>> return False >>> >>> # FIXME: This needs to be tested, but won't work currently # >>> vm.verify_kernel_crash() + >>> logging.debug("vm.verify_kernel_crash() needs to be tested, " + >>> "but won't work currently.") >> >> Bah, right, this is still broken for libvirt. Thanks for the >> reminder :D >> >>> + return True + >>> >>> vm_name = params.get("main_vm") vm = >>> env.get_vm(params["main_vm"]) vm.verify_alive() >>> >>> + # For safety reasons, we'd better back up xmlfile. + >>> vm_xmlfile_bak = vm.backup_xml() + if not vm_xmlfile_bak: + >>> logging.error("Backing up xmlfile failed.") + + vm.connect_uri >>> = params.get("connect_uri", "default") + if vm.connect_uri == >>> 'default': + vm.connect_uri = libvirt_vm.virsh_uri() + >> >> Looks good. >> >>> src_uri = vm.connect_uri dest_uri = >>> params.get("virsh_migrate_desturi") # Identify easy config. >>> mistakes early @@ -75,24 +94,184 @@ def run_virsh_migrate(test, >>> params, env): if dest_uri.count('///') or >>> dest_uri.count('EXAMPLE'): logging.warning(warning_text % >>> ('destination', dest_uri)) >>> >>> + vm_ref = params.get("vm_ref", vm.name) options = >>> params.get("virsh_migrate_options") extra = >>> params.get("virsh_migrate_extra") - dly = >>> int(params.get("virsh_migrate_delay", 10)) - - - >>> do_migration(dly, vm, dest_uri, options, extra) - # Repeat the >>> migration with a recursive call and guaranteed exit - if >>> params.get("virsh_migrate_back", "no") == 'yes': - >>> back_dest_uri = params.get("virsh_migrate_back_desturi", >>> 'default') - back_options = >>> params.get("virsh_migrate_back_options", 'default') - >>> back_extra = params.get("virsh_migrate_back_extra", 'default') - >>> if back_dest_uri == 'default': - back_dest_uri = >>> src_uri - if back_options == 'default': - >>> back_options = options - if back_extra == 'default': - >>> back_extra = extra - do_migration(dly, vm, back_dest_uri, >>> back_options, back_extra) - # Do the uni-direction migration >>> here. + delay = int(params.get("virsh_migrate_delay", 10)) + >>> status_error = params.get("status_error", 'no') + >>> libvirtd_state = params.get("virsh_migrate_libvirtd_state", >>> 'on') + src_state = params.get("virsh_migrate_src_state", >>> "running") + new_nic_mac = "ff:ff:ff:ff:ff:ff" + >>> dest_xmlfile = "" + + exception = False + try: + # >>> Confirm VM can be accessed through network. + >>> time.sleep(delay) + vm_ip = vm.get_address() + >>> s_ping, o_ping = virt_test_utils.ping(vm_ip, count=2, >>> timeout=delay) + logging.info(o_ping) + if s_ping >>> != 0: + raise error.TestError("%s did not respond >>> after %d sec." % (vm.name, delay)) + + # Prepare for >>> --xml. + logging.debug("Preparing new xml file for --xml >>> option.") + if options.count("xml") or >>> extra.count("xml"): + dest_xmlfile = >>> params.get("virsh_migrate_xml", "") + if >>> dest_xmlfile: + ret_attach = >>> vm.attach_interface("--type bridge --source virbr0 --mac %s" % >>> new_nic_mac, True, True) + if not ret_attach: + >>> exception = True + raise >>> error.TestError("Attaching nic to %s failed." % vm.name) + >>> vm_xml_new = vm.get_xml() + logging.debug("Xml >>> file on source: %s" % vm_xml_new) + f = >>> codecs.open(dest_xmlfile, 'wb', encoding='utf-8') + >>> f.write(vm_xml_new) + f.close() + >>> if not os.path.exists(dest_xmlfile): + >>> exception = True + raise >>> error.TestError("Creating %s failed." % dest_xmlfile) + + >>> # Turn VM into certain state. + logging.debug("Turning %s >>> into certain state." % vm.name) + if src_state == >>> "paused": + if vm.is_alive(): + >>> vm.pause() + elif src_state == "shut off": + if >>> vm.is_alive(): + if not vm.shutdown(): + >>> vm.destroy() >> >> For future reference, I think you can do >> vm.destroy(gracefully=True), but this is fine for now. >> >>> + + # Turn libvirtd into certain state. + >>> logging.debug("Turning libvirtd into certain status.") + >>> if libvirtd_state == "off": + >>> libvirt_vm.libvirtd_stop() + + # Test uni-direction >>> migration. + logging.debug("Doing migration test.") + >>> if vm_ref != vm_name: + vm.name = vm_ref # For vm >>> name error testing. >> >> Ahh, I was just wondering what vm_ref was for. Good putting >> comment here. >> >>> + ret_migrate = do_migration(delay, vm, dest_uri, options, >>> extra) + if vm_ref != vm_name: + vm.name = >>> vm_name + + # Recover libvirtd state. + >>> logging.debug("Recovering libvirtd status.") + if >>> libvirtd_state == "off": + >>> libvirt_vm.libvirtd_start() + + # Check vm state on >>> destination. + logging.debug("Checking %s state on %s." % >>> (vm.name, vm.connect_uri)) + if options.count("dname") or >>> extra.count("dname"): + vm.name = >>> extra.split()[1].strip() >> >> For future reference, if you have to code the same thing twice, >> it's a "clue" that you maybe need to just define a function/method. >> However, as noted above, it would be "nice" to have a more robust >> option-checker here, but this is okay for now. >> >>> + check_dest_state = True + dest_state = >>> params.get("virsh_migrate_dest_state", "running") + >>> check_dest_state = check_vm_state(vm, dest_state) + >>> logging.info("Supposed state: %s" % dest_state) + >>> logging.info("Actual state: %s" % vm.state()) + + # >>> Recover VM state. + logging.debug("Recovering %s state." % >>> vm.name) + if src_state == "paused": + >>> vm.resume() + elif src_state == "shut off": + >>> vm.start() + + # Checking for --persistent. + >>> logging.debug("Checking for --persistent option.") + >>> check_dest_persistent = True + if >>> options.count("persistent") or extra.count("persistent"): + >>> if not vm.is_persistent(): + check_dest_persistent >>> = False + + # Checking for --undefinesource. + >>> logging.debug("Checking for --undefinesource option.") + >>> check_src_undefine = True + if >>> options.count("undefinesource") or >>> extra.count("undefinesource"): + >>> logging.info("Verifying<virsh domstate> DOES return an error." >>> + "%s should not exist on %s." % >>> (vm_name, src_uri)) + if >>> libvirt_vm.virsh_domain_exists(vm_name, src_uri): + >>> check_src_undefine = False + + # Checking for --dname. + >>> logging.debug("Checking for --dname option.") + >>> check_dest_dname = True + if options.count("dname") or >>> extra.count("dname"): + dname = >>> extra.split()[1].strip() + if not >>> libvirt_vm.virsh_domain_exists(dname, dest_uri): + >>> check_dest_dname = False + + # Checking for --xml. + >>> logging.debug("Checking for --xml option.") + >>> check_dest_xml = True + if options.count("xml") or >>> extra.count("xml"): + if dest_xmlfile: + >>> vm_dest_xml = vm.get_xml() + logging.info("Xml >>> file on destination: %s" % vm_dest_xml) + if not >>> re.search(new_nic_mac, vm_dest_xml): + >>> check_dest_xml = False + + # Repeat the migration from >>> destination to source. + if >>> params.get("virsh_migrate_back", "no") == 'yes': + >>> back_dest_uri = params.get("virsh_migrate_back_desturi", >>> 'default') + back_options = >>> params.get("virsh_migrate_back_options", 'default') + >>> back_extra = params.get("virsh_migrate_back_extra", 'default') + >>> if back_dest_uri == 'default': + back_dest_uri = >>> src_uri + if back_options == 'default': + >>> back_options = options + if back_extra == 'default': + >>> back_extra = extra + ret_migrate = do_migration(delay, >>> vm, back_dest_uri, back_options, back_extra) + + except >>> Exception, detail: + exception = True + >>> logging.error("%s: %s" % (detail.__class__, detail)) + + + # >>> Whatever error occurs, we have to clean up all environment. + >>> # Make sure vm.connect_uri is the destination uri. + >>> vm.connect_uri = dest_uri + if options.count("dname") or >>> extra.count("dname"): + # Use the VM object to remove + >>> vm.name = extra.split()[1].strip() >> >> Ahh, three times, see it would help to have a function to do this >> :) It's okay for now though since it's such a simplistic check. >> >>> + cleanup_dest(vm, src_uri) + vm.name = vm_name >>> else: cleanup_dest(vm, src_uri) + + # Recover source (just in >>> case). + # vm.connect_uri has been set back to src_uri in >>> cleanup_dest(). >> >> Good to put this comment here, guarantee no confusion. >> >>> + if not libvirt_vm.virsh_domain_exists(vm_name, src_uri): + >>> vm.define(vm_xmlfile_bak) >> >> This we can improve with my new xml_utils class, it will >> automatically take backup. What you have here is fine for now >> since my code is still experimental. >> >>> + else: + #if not vm.shutdown(): + vm.destroy() >>> + + # Cleanup source. + if os.path.exists(vm_xmlfile_bak): >>> + os.remove(vm_xmlfile_bak) + logging.info("%s >>> removed." % vm_xmlfile_bak) + if >>> os.path.exists(dest_xmlfile): + os.remove(dest_xmlfile) + >>> + if exception: + raise error.TestError("Error >>> occurred. \n%s: %s" % (detail.__class__, detail)) + + # Check >>> test result. + if status_error == 'yes': + if >>> ret_migrate: + raise error.TestFail("Migration >>> finished with unexpected status.") + else: + if not >>> ret_migrate: + raise error.TestFail("Migration >>> finished with unexpected status.") + if not >>> check_dest_state: + raise error.TestFail("Wrong VM >>> state on destination.") + if not check_dest_persistent: + >>> raise error.TestFail("VM is not persistent on destination.") + >>> if not check_src_undefine: + raise error.TestFail("VM >>> is not undefined on source.") + if not check_dest_dname: + >>> raise error.TestFail("Wrong VM name %s on destination." % dname) >>> + if not check_dest_xml: + raise >>> error.TestFail("Wrong xml configuration on destination.") >> >> This is becomming very complicated test module, but the code reads >> very clean, style looks good, and it's well commented. There are a >> few areas for improvement (nothing is ever perfect :) but overall >> it's very good. I'll tripple check it through pylint and then see >> about getting it committed to "next" branch for integration >> testing. Nice job, thanks for following through. >> > -- Chris Evich, RHCA, RHCE, RHCDS, RHCSS Quality Assurance Engineer e-mail: cevich + `@' + redhat.com o: 1-888-RED-HAT1 x44214 _______________________________________________ Autotest mailing list Autotest@test.kernel.org http://test.kernel.org/cgi-bin/mailman/listinfo/autotest