[PATCH 0 of 2] [TEST] Adding new tc for verifying Migration indication for KVM.

# HG changeset patch # User Deepti B. Kalakeri <deeptik@linux.vnet.ibm.com> # Date 1246972788 25200 # Node ID 9903b1d91bd966f453392ddbd0378feb50a4f771 # Parent 479f287a17fd08e4e22ac37459393f6f8327315a [TEST] Modified the indication_tester.py to support MigrationIndications. Modified indication_tester.py to include - sub_ind() --> Subscribe for the indications to be watched. - handle_request() --> Filters the required indications. - poll_for_ind() --> Wait for the required indications to be triggered. Tested with KVM and current sources on F10. Signed-off-by: Deepti B. Kalakeri <deeptik@linux.vnet.ibm.com> diff -r 479f287a17fd -r 9903b1d91bd9 suites/libvirt-cim/lib/XenKvmLib/indication_tester.py --- a/suites/libvirt-cim/lib/XenKvmLib/indication_tester.py Tue Jun 30 06:53:22 2009 -0700 +++ b/suites/libvirt-cim/lib/XenKvmLib/indication_tester.py Tue Jul 07 06:19:48 2009 -0700 @@ -11,6 +11,13 @@ import httplib import base64 from xml.dom.minidom import parse, parseString +from os import kill, WNOHANG +from signal import SIGKILL +from CimTest.Globals import logger +from XenKvmLib.vxml import set_default +from XenKvmLib.classes import get_typed_class +from CimTest.ReturnCodes import PASS, FAIL +from os import waitpid, kill, fork, _exit, WNOHANG def filter_xml(name, type, ns, sysname): return """ @@ -381,6 +388,80 @@ print "CreateSubscription:\n%s\n" % subscript_str print "DeleteSubscription:\n%s\n" % del_subscript_str +def sub_ind(ip, virt, ind_names): + dict = set_default(ip) + sub_list = {} + port = 5 + + for ind, iname in ind_names.iteritems(): + ind_name = get_typed_class(virt, iname) + + sub_name = "Test%s" % ind_name + port += 1 + + sub = CIMIndicationSubscription(sub_name, ind_name, + dict['default_ns'], + dict['default_print_ind'], + dict['default_sysname'], + port) + sub.subscribe(dict['default_url'], dict['default_auth']) + logger.info("Watching for %s", iname) + ind_names[ind] = ind_name + sub_list[ind] = sub + + return sub_list, ind_names, dict + +def handle_request(sub, ind_name, dict, exp_ind_ct): + #sfcb delivers indications to all registrations, even if the indication + #isn't what the registration was subscribed to. So, for modified and + #deleted indications, we must loop through until the indication we are + #looking for is triggered. + for i in range(0, exp_ind_ct): + sub.server.handle_request() + if len(sub.server.indications) < 1: + logger.error("No valid indications received") + return FAIL + + if str(sub.server.indications[0]) == ind_name: + sub.unsubscribe(dict['default_auth']) + logger.info("Cancelling subscription for %s", ind_name) + return PASS + else: + sub.server.indications.remove(sub.server.indications[0]) + + logger.error("Did not recieve indication %s", ind_name) + return FAIL + +def poll_for_ind(pid, ind_name, timeout=20): + status = FAIL + for i in range(0, timeout): + pw = waitpid(pid, WNOHANG) + + # If pid exits, waitpid returns [pid, return_code] + # If pid is still running, waitpid returns [0, 0] + # Only return a success if waitpid returns the expected pid + # and the return code is 0. + if pw[0] == pid and pw[1] == 0: + logger.info("Great, got '%s' indication successfully", ind_name) + status = PASS + break + elif pw[1] == 0 and i < timeout: + if i % 10 == 0: + logger.info("In child, waiting for '%s' indication", ind_name) + sleep(1) + else: + # Time is up and waitpid never returned the expected pid + if pw[0] != pid: + logger.error("Waited too long for '%s' indication", ind_name) + kill(pid, SIGKILL) + else: + logger.error("Received Indication error: '%d'", pw[1]) + + status = FAIL + break + + return status + def main(): usage = "usage: %prog [options] provider\nex: %prog CIM_InstModification" parser = OptionParser(usage)

Deepti B. Kalakeri wrote:
# HG changeset patch # User Deepti B. Kalakeri <deeptik@linux.vnet.ibm.com> # Date 1246972788 25200 # Node ID 9903b1d91bd966f453392ddbd0378feb50a4f771 # Parent 479f287a17fd08e4e22ac37459393f6f8327315a [TEST] Modified the indication_tester.py to support MigrationIndications.
Modified indication_tester.py to include - sub_ind() --> Subscribe for the indications to be watched. - handle_request() --> Filters the required indications. - poll_for_ind() --> Wait for the required indications to be triggered.
Tested with KVM and current sources on F10. Signed-off-by: Deepti B. Kalakeri <deeptik@linux.vnet.ibm.com>
diff -r 479f287a17fd -r 9903b1d91bd9 suites/libvirt-cim/lib/XenKvmLib/indication_tester.py
I'm torn on whether to include these changes in this file. Really, the indication_tester.py was a standalone tool that wasn't originally included in the cimtest tree. It was pulled in later so that the automated test cases could leverage its functionality. Anytime a change is made to other copy, the changes need to be pushed to the other so that the two remain in sync. These changes won't ever be used by the indication_tester.py itself, so I'm inclined to suggest moving them into their own module. Generally, I'm against having lots of different modules - I am in favor of consolidating where appropriate. However, I think this makes sense given that indication_tester is a special case. -- Kaitlin Rupert IBM Linux Technology Center kaitlin@linux.vnet.ibm.com

Kaitlin Rupert wrote:
Deepti B. Kalakeri wrote:
# HG changeset patch # User Deepti B. Kalakeri <deeptik@linux.vnet.ibm.com> # Date 1246972788 25200 # Node ID 9903b1d91bd966f453392ddbd0378feb50a4f771 # Parent 479f287a17fd08e4e22ac37459393f6f8327315a [TEST] Modified the indication_tester.py to support MigrationIndications.
Modified indication_tester.py to include - sub_ind() --> Subscribe for the indications to be watched. - handle_request() --> Filters the required indications. - poll_for_ind() --> Wait for the required indications to be triggered.
Tested with KVM and current sources on F10. Signed-off-by: Deepti B. Kalakeri <deeptik@linux.vnet.ibm.com>
diff -r 479f287a17fd -r 9903b1d91bd9 suites/libvirt-cim/lib/XenKvmLib/indication_tester.py
I'm torn on whether to include these changes in this file. Really, the indication_tester.py was a standalone tool that wasn't originally included in the cimtest tree. It was pulled in later so that the automated test cases could leverage its functionality.
Anytime a change is made to other copy, the changes need to be pushed to the other so that the two remain in sync. These changes won't ever be used by the indication_tester.py itself, so I'm inclined to suggest moving them into their own module.
Generally, I'm against having lots of different modules - I am in favor of consolidating where appropriate. However, I think this makes sense given that indication_tester is a special case.
I agree with you.. I too came up with the same problem of whether to extend the indication_tester.py to include the new fns(). I have moved the required fns() for Indications to a new file called indications.py, so now indication_tester.py is independent to be moved after the CSI/01_created_indication.py is modified to use the indications.py fns(). I think since we have a different dir which standalone tc, we can move the indication_tester.py to suites/libvirt-cim/misc_cimtests/, and how about migration_tester.py ...thoughts ?? -- Thanks and Regards, Deepti B. Kalakeri IBM Linux Technology Center deeptik@linux.vnet.ibm.com

Anytime a change is made to other copy, the changes need to be pushed to the other so that the two remain in sync. These changes won't ever be used by the indication_tester.py itself, so I'm inclined to suggest moving them into their own module.
Generally, I'm against having lots of different modules - I am in favor of consolidating where appropriate. However, I think this makes sense given that indication_tester is a special case.
I agree with you.. I too came up with the same problem of whether to extend the indication_tester.py to include the new fns(). I have moved the required fns() for Indications to a new file called indications.py, so now indication_tester.py is independent to be moved after the CSI/01_created_indication.py is modified to use the indications.py fns(). I think since we have a different dir which standalone tc, we can move the indication_tester.py to suites/libvirt-cim/misc_cimtests/, and how about migration_tester.py ...thoughts ??
I think this is an excellent idea. The tests will need to import CIMIndicationSubscription from indication_tester still, but it doesn't matter where the tester is located. -- Kaitlin Rupert IBM Linux Technology Center kaitlin@linux.vnet.ibm.com

# HG changeset patch # User Deepti B. Kalakeri<deeptik@linux.vnet.ibm.com> # Date 1246973869 25200 # Node ID 26883d6afdb51457e0ed7e11e94fce6eb3470f2e # Parent 9903b1d91bd966f453392ddbd0378feb50a4f771 [TEST] Adding new tc to verify Migration indications for KVM. Tested with KVM and current sources on F10. Signed-off-by: Deepti B. Kalakeri <deeptik@linux.vnet.ibm.com> diff -r 9903b1d91bd9 -r 26883d6afdb5 suites/libvirt-cim/cimtest/ComputerSystemMigrationJobIndication/01_csmig_ind_for_offline_mig.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/suites/libvirt-cim/cimtest/ComputerSystemMigrationJobIndication/01_csmig_ind_for_offline_mig.py Tue Jul 07 06:37:49 2009 -0700 @@ -0,0 +1,201 @@ +#!/usr/bin/python +# +# Copyright 2009 IBM Corp. +# +# Authors: +# Deepti B. Kalakeri <deeptik@linux.vnet.ibm.com> +# +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# +# This testcase is used to verify the Created|Modified|Deleted +# Migration Indications for offline VM Migration. +# +# Date : 06-07-2009 +# + +import sys +import os +from socket import gethostname +from XenKvmLib import vxml +from XenKvmLib.xm_virt_util import domain_list, net_list +from CimTest.Globals import logger +from XenKvmLib.const import do_main, default_network_name +from CimTest.ReturnCodes import PASS, FAIL +from XenKvmLib.classes import get_typed_class +from XenKvmLib.vsmigrations import check_mig_support, local_remote_migrate +from XenKvmLib.common_util import poll_for_state_change, create_netpool_conf,\ + destroy_netpool +from XenKvmLib.vxml import set_default +from os import waitpid, kill, fork, _exit +from signal import SIGKILL +from XenKvmLib.indication_tester import CIMIndicationSubscription, sub_ind, \ + handle_request, poll_for_ind + +sup_types = ['KVM', 'Xen'] + +REQUESTED_STATE = 3 + +def setup_guest(test_dom, ip, virt): + virt_xml = vxml.get_class(virt) + cxml = virt_xml(test_dom) + ret = cxml.cim_define(ip) + if not ret: + logger.error("Error define domain %s", test_dom) + return FAIL, cxml + + status, dom_cs = poll_for_state_change(ip, virt, test_dom, + REQUESTED_STATE) + if status != PASS: + cxml.undefine(test_dom) + logger.error("'%s' didn't change state as expected" % test_dom) + return FAIL, cxml + + return PASS, cxml + +def cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname, clean_net=True): + # Clean the domain on target machine. + # This is req when migration is successful, also when migration is not + # completely successful VM might be created on the target machine + # and hence need to clean. + target_list = domain_list(t_sysname, virt) + if target_list != None and test_dom in target_list: + ret_value = cxml.undefine(t_sysname) + if not ret_value: + logger.info("Failed to undefine the migrated domain '%s' on '%s'", + test_dom, t_sysname) + + if clean_net != True: + return + + # clean the networkpool created on the remote machine + target_net_list = net_list(t_sysname, virt) + if target_net_list != None and default_network_name in target_net_list: + ret_value = destroy_netpool(t_sysname, virt, default_network_name) + if ret_value != PASS: + logger.info("Unable to destroy networkpool '%s' on '%s'", + default_network_name, t_sysname) + + # Remote Migration not Successful, clean the domain on src machine + src_list = domain_list(s_sysname, virt) + if src_list != None and test_dom in src_list: + ret_value = cxml.undefine(s_sysname) + if not ret_value: + logger.info("Failed to undefine the domain '%s' on source '%s'", + test_dom, s_sysname) + + +def gen_indication(test_dom, s_sysname, virt, t_sysname): + cxml = None + try: + status, cxml = setup_guest(test_dom, s_sysname, virt) + if status != PASS: + logger.error("Error setting up the guest") + return status, None + + # create the networkpool used in the domain to be migrated + # on the target machine. + t_net_list = net_list(t_sysname, virt) + if t_net_list != None and default_network_name not in t_net_list: + status, netpool = create_netpool_conf(t_sysname, virt, + net_name=default_network_name) + if status != PASS: + raise Exception("Unable to create network pool '%s' on '%s'" + % (default_network_name, t_sysname)) + + # Migrate the test_dom to t_sysname. + # Enable remote migration by setting remote_migrate=1 + status = local_remote_migrate(s_sysname, t_sysname, virt, + remote_migrate=1, + guest_name=test_dom, + mtype='offline') + + except Exception, details: + logger.error("Exception details :%s", details) + return FAIL, cxml + + return status, cxml + + + +@do_main(sup_types) +def main(): + options = main.options + virt = options.virt + status, s_sysname, t_sysname = check_mig_support(virt, options) + if status != PASS: + return status + + status = FAIL + test_dom = 'VM_frm_' + gethostname() + ind_names = { + 'create' : 'ComputerSystemMigrationJobCreatedIndication', + 'modify' : 'ComputerSystemMigrationJobModifiedIndication', + 'delete' : 'ComputerSystemMigrationJobDeletedIndication' + } + + sub_list, ind_names, dict = sub_ind(s_sysname, virt, ind_names) + for ind in ind_names.keys(): + sub = sub_list[ind] + ind_name = ind_names[ind] + logger.info("\n Verifying '%s' indications ....", ind_name) + try: + pid = fork() + if pid == 0: + status = handle_request(sub, ind_name, dict, + len(ind_names.keys())) + if status != PASS: + _exit(1) + + _exit(0) + else: + try: + status, cxml = gen_indication(test_dom, s_sysname, + virt, t_sysname) + if status != PASS: + kill(pid, SIGKILL) + raise Exception("Unable to generate indication") + + status = poll_for_ind(pid, ind_name) + except Exception, details: + kill(pid, SIGKILL) + raise Exception(details) + + except Exception, details: + logger.error("Exception: %s", details) + status = FAIL + + if status != PASS: + break + + cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname, clean_net=False) + + + #Make sure all subscriptions are really unsubscribed + for ind, sub in sub_list.iteritems(): + sub.unsubscribe(dict['default_auth']) + logger.info("Cancelling subscription for %s", ind_names[ind]) + + cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname) + return status + + +if __name__ == "__main__": + sys.exit(main()) +

+import sys +import os
You have an import os statement later on, so no need to include this one.
+from socket import gethostname +from XenKvmLib import vxml
Same here, you have an import vxml statement later on; this one can be removed.
+ if status != PASS: + break
Instead of breaking here, you can break after calling cleanup_guest_netpool(), this way, you won't need to call cleanup_guest_netpool() after you unsubscribe the indications.
+ + cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname, clean_net=False) + + + #Make sure all subscriptions are really unsubscribed + for ind, sub in sub_list.iteritems(): + sub.unsubscribe(dict['default_auth']) + logger.info("Cancelling subscription for %s", ind_names[ind]) + + cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname) + return status +
-- Kaitlin Rupert IBM Linux Technology Center kaitlin@linux.vnet.ibm.com

Kaitlin Rupert wrote:
+import sys +import os
You have an import os statement later on, so no need to include this one.
+from socket import gethostname +from XenKvmLib import vxml
Same here, you have an import vxml statement later on; this one can be removed.
+ if status != PASS: + break
Instead of breaking here, you can break after calling cleanup_guest_netpool(), this way, you won't need to call cleanup_guest_netpool() after you unsubscribe the indications.
The call to cleanup_guest_netpool() are little different .. the call after the status check is designed to not delete the network pool that is created on the target machine so that we can reuse it through the loop without having to create it every time we want to migrate the guest.
+ + cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname, clean_net=False) + + + #Make sure all subscriptions are really unsubscribed + for ind, sub in sub_list.iteritems(): + sub.unsubscribe(dict['default_auth']) + logger.info("Cancelling subscription for %s", ind_names[ind]) + + cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname) + return status +
-- Thanks and Regards, Deepti B. Kalakeri IBM Linux Technology Center deeptik@linux.vnet.ibm.com

Deepti B Kalakeri wrote:
Kaitlin Rupert wrote:
+import sys +import os
You have an import os statement later on, so no need to include this one.
+from socket import gethostname +from XenKvmLib import vxml
Same here, you have an import vxml statement later on; this one can be removed.
+ if status != PASS: + break
Instead of breaking here, you can break after calling cleanup_guest_netpool(), this way, you won't need to call cleanup_guest_netpool() after you unsubscribe the indications.
The call to cleanup_guest_netpool() are little different .. the call after the status check is designed to not delete the network pool that is created on the target machine so that we can reuse it through the loop without having to create it every time we want to migrate the guest.
Ah, yes -thanks for the correction. I missed the "clean_net=False" param in the call below.
+ + cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname, clean_net=False) + + + #Make sure all subscriptions are really unsubscribed + for ind, sub in sub_list.iteritems(): + sub.unsubscribe(dict['default_auth']) + logger.info("Cancelling subscription for %s", ind_names[ind]) + + cleanup_guest_netpool(virt, cxml, test_dom, t_sysname, + s_sysname) + return status +
-- Kaitlin Rupert IBM Linux Technology Center kaitlin@linux.vnet.ibm.com
participants (3)
-
Deepti B Kalakeri
-
Deepti B. Kalakeri
-
Kaitlin Rupert