All of lore.kernel.org
 help / color / mirror / Atom feed
* [KVM-AUTOTEST PATCH 1/7] KVM test: simplify MAC address management
@ 2010-10-24 11:01 Michael Goldish
  2010-10-24 11:01 ` [KVM-AUTOTEST PATCH 2/7] KVM test: VM.get_address(): fix handling of multiple NICs Michael Goldish
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Goldish @ 2010-10-24 11:01 UTC (permalink / raw)
  To: autotest, kvm

- Remove the VM.mac_prefix attribute
- Remove the 'root_dir' parameter from generate_mac_address() and
  free_mac_address()
- Remove the 'prefix' parameter from generate_mac_address()
- Remove the explicit setting and clearing of bits in the most significant
  byte (it is fixed to 0x9A anyway)
- Remove the 'shareable' parameter from set_mac_address() (no longer required)
- Remove the 'preserve_mac' parameter from VM.clone() and replace it with
  'mac_source' in VM.create()
- Remove overly verbose debug messages from free_mac_address()
- Replace VM.free_mac_addresses() with VM.free_mac_address()
- Use _open_mac_pool() and _close_mac_pool() to save code
- Merge _generate_mac_address_prefix() with generate_mac_address_prefix()
- Concentrate all functions that access the MAC address pool in the same module
  (kvm_utils.py)
- Minor style changes

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_test_utils.py   |    2 +-
 client/tests/kvm/kvm_utils.py        |  185 +++++++++++++++++----------------
 client/tests/kvm/kvm_vm.py           |   93 ++++++------------
 client/tests/kvm/tests/mac_change.py |   11 +--
 4 files changed, 130 insertions(+), 161 deletions(-)

diff --git a/client/tests/kvm/kvm_test_utils.py b/client/tests/kvm/kvm_test_utils.py
index 585e194..d9c5a6e 100644
--- a/client/tests/kvm/kvm_test_utils.py
+++ b/client/tests/kvm/kvm_test_utils.py
@@ -187,7 +187,7 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
 
     # Clone the source VM and ask the clone to wait for incoming migration
     dest_vm = vm.clone()
-    if not dest_vm.create(extra_params=mig_extra_params):
+    if not dest_vm.create(extra_params=mig_extra_params, mac_source=vm):
         raise error.TestError("Could not create dest VM")
 
     try:
diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py
index a2b0a3f..778637d 100644
--- a/client/tests/kvm/kvm_utils.py
+++ b/client/tests/kvm/kvm_utils.py
@@ -11,6 +11,17 @@ from autotest_lib.client.common_lib import error, logging_config
 import kvm_subprocess
 
 
+def _lock_file(filename):
+    f = open(filename, "w")
+    fcntl.lockf(f, fcntl.LOCK_EX)
+    return f
+
+
+def _unlock_file(f):
+    fcntl.lockf(f, fcntl.LOCK_UN)
+    f.close()
+
+
 def dump_env(obj, filename):
     """
     Dump KVM test environment to a file.
@@ -83,119 +94,113 @@ def get_sub_dict_names(dict, keyword):
 
 # Functions related to MAC/IP addresses
 
-def _generate_mac_address_prefix():
-    """
-    Generate a MAC address prefix. By convention we will set KVM autotest
-    MAC addresses to start with 0x9a.
-    """
-    r = random.SystemRandom()
-    l = [0x9a, r.randint(0x00, 0x7f), r.randint(0x00, 0x7f),
-         r.randint(0x00, 0xff)]
-    prefix = ':'.join(map(lambda x: "%02x" % x, l)) + ":"
-    return prefix
+def _open_mac_pool(lock_mode):
+    lock_file = open("/tmp/mac_lock", "w+")
+    fcntl.lockf(lock_file, lock_mode)
+    pool = shelve.open("/tmp/address_pool")
+    return pool, lock_file
 
 
-def generate_mac_address_prefix():
+def _close_mac_pool(pool, lock_file):
+    pool.close()
+    fcntl.lockf(lock_file, fcntl.LOCK_UN)
+    lock_file.close()
+
+
+def _generate_mac_address_prefix(mac_pool):
     """
     Generate a random MAC address prefix and add it to the MAC pool dictionary.
     If there's a MAC prefix there already, do not update the MAC pool and just
-    return what's in there.
-    """
-    lock_file = open("/tmp/mac_lock", 'w')
-    fcntl.lockf(lock_file.fileno() ,fcntl.LOCK_EX)
-    mac_pool = shelve.open("/tmp/address_pool", writeback=False)
+    return what's in there. By convention we will set KVM autotest MAC
+    addresses to start with 0x9a.
 
-    if mac_pool.get('prefix'):
-        prefix = mac_pool.get('prefix')
-        logging.debug('Retrieved previously generated MAC prefix for this '
-                      'host: %s', prefix)
+    @param mac_pool: The MAC address pool object.
+    @return: The MAC address prefix.
+    """
+    if "prefix" in mac_pool:
+        prefix = mac_pool["prefix"]
+        logging.debug("Used previously generated MAC address prefix for this "
+                      "host: %s", prefix)
     else:
-        prefix = _generate_mac_address_prefix()
-        mac_pool['prefix'] = prefix
-        logging.debug('Generated MAC address prefix for this host: %s', prefix)
-
-    mac_pool.close()
-    fcntl.lockf(lock_file.fileno(), fcntl.LOCK_UN)
-    lock_file.close()
-
+        r = random.SystemRandom()
+        prefix = "9a:%02x:%02x:%02x:" % (r.randint(0x00, 0xff),
+                                         r.randint(0x00, 0xff),
+                                         r.randint(0x00, 0xff))
+        mac_pool["prefix"] = prefix
+        logging.debug("Generated MAC address prefix for this host: %s", prefix)
     return prefix
 
 
-def generate_mac_address(root_dir, instance_vm, nic_index, prefix=None):
+def generate_mac_address(vm_instance, nic_index):
     """
-    Random generate a MAC address and add it to the MAC pool.
+    Randomly generate a MAC address and add it to the MAC address pool.
 
-    Try to generate macaddress based on the mac address prefix, add it to a
-    dictionary 'address_pool'.
-    key = VM instance + nic index, value = mac address
-    {['20100310-165222-Wt7l:0'] : 'AE:9D:94:6A:9b:f9'}
+    Try to generate a MAC address based on a randomly generated MAC address
+    prefix and add it to a persistent dictionary.
+    key = VM instance + NIC index, value = MAC address
+    e.g. {'20100310-165222-Wt7l:0': '9a:5d:94:6a:9b:f9'}
 
-    @param root_dir: Root dir for kvm.
-    @param instance_vm: Here we use instance of vm.
-    @param nic_index: The index of nic.
-    @param prefix: Prefix of MAC address.
+    @param vm_instance: The instance attribute of a VM.
+    @param nic_index: The index of the NIC.
     @return: MAC address string.
     """
-    if prefix is None:
-        prefix = generate_mac_address_prefix()
-
-    r = random.SystemRandom()
-    lock_file = open("/tmp/mac_lock", 'w')
-    fcntl.lockf(lock_file.fileno() ,fcntl.LOCK_EX)
-    mac_pool = shelve.open("/tmp/address_pool", writeback=False)
-    found = False
-    key = "%s:%s" % (instance_vm, nic_index)
-
-    if mac_pool.get(key):
-        found = True
-        mac = mac_pool.get(key)
-
-    while not found:
-        suffix = "%02x:%02x" % (r.randint(0x00,0xfe),
-                                r.randint(0x00,0xfe))
-        mac = prefix + suffix
-        mac_list = mac.split(":")
-        # Clear multicast bit
-        mac_list[0] = int(mac_list[0],16) & 0xfe
-        # Set local assignment bit (IEEE802)
-        mac_list[0] = mac_list[0] | 0x02
-        mac_list[0] = "%02x" % mac_list[0]
-        mac = ":".join(mac_list)
-        if mac in [mac_pool.get(k) for k in mac_pool.keys()]:
+    mac_pool, lock_file = _open_mac_pool(fcntl.LOCK_EX)
+    key = "%s:%s" % (vm_instance, nic_index)
+    if key in mac_pool:
+        mac = mac_pool[key]
+    else:
+        prefix = _generate_mac_address_prefix(mac_pool)
+        r = random.SystemRandom()
+        while key not in mac_pool:
+            mac = prefix + "%02x:%02x" % (r.randint(0x00, 0xff),
+                                          r.randint(0x00, 0xff))
+            if mac in mac_pool.values():
                 continue
-        mac_pool[key] = mac
-        found = True
-    logging.debug("Generated MAC address for NIC %s: %s ", key, mac)
-
-    mac_pool.close()
-    fcntl.lockf(lock_file.fileno(), fcntl.LOCK_UN)
-    lock_file.close()
+            mac_pool[key] = mac
+            logging.debug("Generated MAC address for NIC %s: %s", key, mac)
+    _close_mac_pool(mac_pool, lock_file)
     return mac
 
 
-def free_mac_address(root_dir, instance_vm, nic_index):
+def free_mac_address(vm_instance, nic_index):
     """
-    Free mac address from address pool
+    Remove a MAC address from the address pool.
 
-    @param root_dir: Root dir for kvm
-    @param instance_vm: Here we use instance attribute of vm
-    @param nic_index: The index of nic
+    @param vm_instance: The instance attribute of a VM.
+    @param nic_index: The index of the NIC.
     """
-    lock_file = open("/tmp/mac_lock", 'w')
-    fcntl.lockf(lock_file.fileno() ,fcntl.LOCK_EX)
-    mac_pool = shelve.open("/tmp/address_pool", writeback=False)
-    key = "%s:%s" % (instance_vm, nic_index)
-    if not mac_pool or (not key in mac_pool.keys()):
-        logging.debug("NIC not present in the MAC pool, not modifying pool")
-        logging.debug("NIC: %s" % key)
-        logging.debug("Contents of MAC pool: %s" % mac_pool)
-    else:
-        logging.debug("Freeing MAC addr for NIC %s: %s", key, mac_pool[key])
-        mac_pool.pop(key)
+    mac_pool, lock_file = _open_mac_pool(fcntl.LOCK_EX)
+    key = "%s:%s" % (vm_instance, nic_index)
+    if key in mac_pool:
+        logging.debug("Freeing MAC address for NIC %s: %s", key, mac_pool[key])
+        del mac_pool[key]
+    _close_mac_pool(mac_pool, lock_file)
 
-    mac_pool.close()
-    fcntl.lockf(lock_file.fileno(), fcntl.LOCK_UN)
-    lock_file.close()
+
+def set_mac_address(vm_instance, nic_index, mac):
+    """
+    Set a MAC address in the pool.
+
+    @param vm_instance: The instance attribute of a VM.
+    @param nic_index: The index of the NIC.
+    """
+    mac_pool, lock_file = _open_mac_pool(fcntl.LOCK_EX)
+    mac_pool["%s:%s" % (vm_instance, nic_index)] = mac
+    _close_mac_pool(mac_pool, lock_file)
+
+
+def get_mac_address(vm_instance, nic_index):
+    """
+    Return a MAC address from the pool.
+
+    @param vm_instance: The instance attribute of a VM.
+    @param nic_index: The index of the NIC.
+    @return: MAC address string.
+    """
+    mac_pool, lock_file = _open_mac_pool(fcntl.LOCK_SH)
+    mac = mac_pool.get("%s:%s" % (vm_instance, nic_index))
+    _close_mac_pool(mac_pool, lock_file)
+    return mac
 
 
 def mac_str_to_int(addr):
diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index 848ff63..51e7cfa 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -109,16 +109,15 @@ class VM:
         self.serial_console = None
         self.redirs = {}
         self.vnc_port = 5900
-        self.uuid = None
         self.monitors = []
         self.pci_assignable = None
+        self.netdev_id = []
+        self.uuid = None
 
         self.name = name
         self.params = params
         self.root_dir = root_dir
         self.address_cache = address_cache
-        self.mac_prefix = params.get('mac_prefix')
-        self.netdev_id = []
 
         # Find a unique identifier for this VM
         while True:
@@ -127,12 +126,8 @@ class VM:
             if not glob.glob("/tmp/*%s" % self.instance):
                 break
 
-        if self.mac_prefix is None:
-            self.mac_prefix = kvm_utils.generate_mac_address_prefix()
-
 
-    def clone(self, name=None, params=None, root_dir=None,
-                    address_cache=None, preserve_mac=True):
+    def clone(self, name=None, params=None, root_dir=None, address_cache=None):
         """
         Return a clone of the VM object with optionally modified parameters.
         The clone is initially not alive and needs to be started using create().
@@ -143,7 +138,6 @@ class VM:
         @param params: Optional new VM creation parameters
         @param root_dir: Optional new base directory for relative filenames
         @param address_cache: A dict that maps MAC addresses to IP addresses
-        @param preserve_mac: Clone mac address or not.
         """
         if name is None:
             name = self.name
@@ -153,20 +147,7 @@ class VM:
             root_dir = self.root_dir
         if address_cache is None:
             address_cache = self.address_cache
-        vm = VM(name, params, root_dir, address_cache)
-        if preserve_mac:
-            vlan = 0
-            for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
-                nic_params = kvm_utils.get_sub_dict(params, nic_name)
-                vm.set_mac_address(self.get_mac_address(vlan), vlan, True)
-                vlan += 1
-        return vm
-
-
-    def free_mac_addresses(self):
-        nic_num = len(kvm_utils.get_sub_dict_names(self.params, "nics"))
-        for i in range(nic_num):
-            kvm_utils.free_mac_address(self.root_dir, self.instance, i)
+        return VM(name, params, root_dir, address_cache)
 
 
     def make_qemu_command(self, name=None, params=None, root_dir=None):
@@ -423,16 +404,7 @@ class VM:
         for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
             nic_params = kvm_utils.get_sub_dict(params, nic_name)
             # Handle the '-net nic' part
-            mac = None
-            if "address_index" in nic_params:
-                mac = kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
-                self.set_mac_address(mac=mac, nic_index=vlan)
-            else:
-                mac = kvm_utils.generate_mac_address(self.root_dir,
-                                                     self.instance,
-                                                     vlan,
-                                                     self.mac_prefix)
-
+            mac = self.get_mac_address(vlan)
             qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac,
                                 self.netdev_id[vlan],
                                 nic_params.get("nic_extra_params"))
@@ -536,7 +508,8 @@ class VM:
 
 
     def create(self, name=None, params=None, root_dir=None,
-               for_migration=False, timeout=5.0, extra_params=None):
+               for_migration=False, timeout=5.0, extra_params=None,
+               mac_source=None):
         """
         Start the VM by running a qemu command.
         All parameters are optional. The following applies to all parameters
@@ -551,6 +524,8 @@ class VM:
         option
         @param extra_params: extra params for qemu command.e.g -incoming option
         Please use this parameter instead of for_migration.
+        @param mac_source: A VM object from which to copy MAC addresses. If not
+                specified, new addresses will be generated.
         """
         self.destroy()
 
@@ -625,6 +600,15 @@ class VM:
                 self.uuid = f.read().strip()
                 f.close()
 
+            # Generate or copy MAC addresses for all NICs
+            num_nics = len(kvm_utils.get_sub_dict_names(params, "nics"))
+            for vlan in range(num_nics):
+                mac = mac_source and mac_source.get_mac_address(vlan)
+                if mac:
+                    kvm_utils.set_mac_address(self.instance, vlan, mac)
+                else:
+                    kvm_utils.generate_mac_address(self.instance, vlan)
+
             # Assign a PCI assignable device
             self.pci_assignable = None
             pa_type = params.get("pci_assignable")
@@ -799,14 +783,10 @@ class VM:
                                       "to go down...")
                         if kvm_utils.wait_for(self.is_dead, 60, 1, 1):
                             logging.debug("VM is down, freeing mac address.")
-                            self.free_mac_addresses()
                             return
                     finally:
                         session.close()
 
-            # Free mac addresses
-            self.free_mac_addresses()
-
             if self.monitor:
                 # Try to destroy with a monitor command
                 logging.debug("Trying to kill VM with monitor command...")
@@ -846,6 +826,9 @@ class VM:
                     os.unlink(f)
                 except OSError:
                     pass
+            num_nics = len(kvm_utils.get_sub_dict_names(self.params, "nics"))
+            for vlan in range(num_nics):
+                self.free_mac_address(vlan)
 
 
     @property
@@ -1002,41 +985,25 @@ class VM:
 
     def get_mac_address(self, nic_index=0):
         """
-        Return the macaddr of guest nic.
+        Return the MAC address of a NIC.
 
         @param nic_index: Index of the NIC
         """
-        mac_pool = shelve.open("/tmp/address_pool", writeback=False)
-        key = "%s:%s" % (self.instance, nic_index)
-        if key in mac_pool.keys():
-            return mac_pool[key]
+        nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
+        nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
+        if nic_params.get("address_index"):
+            return kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
         else:
-            return None
+            return kvm_utils.get_mac_address(self.instance, nic_index)
 
 
-    def set_mac_address(self, mac, nic_index=0, shareable=False):
+    def free_mac_address(self, nic_index=0):
         """
-        Set mac address for guest. Note: It just update address pool.
+        Free a NIC's MAC address.
 
-        @param mac: address will set to guest
         @param nic_index: Index of the NIC
-        @param shareable: Where VM can share mac with other VM or not.
         """
-        lock_file = open("/tmp/mac_lock", 'w')
-        fcntl.lockf(lock_file.fileno() ,fcntl.LOCK_EX)
-        mac_pool = shelve.open("/tmp/address_pool", writeback=False)
-        key = "%s:%s" % (self.instance, nic_index)
-
-        if not mac in [mac_pool[i] for i in mac_pool.keys()]:
-            mac_pool[key] = mac
-        else:
-            if shareable:
-                mac_pool[key] = mac
-            else:
-                logging.error("MAC address %s is already in use!", mac)
-        mac_pool.close()
-        fcntl.lockf(lock_file.fileno(), fcntl.LOCK_UN)
-        lock_file.close()
+        kvm_utils.free_mac_address(self.instance, nic_index)
 
 
     def get_pid(self):
diff --git a/client/tests/kvm/tests/mac_change.py b/client/tests/kvm/tests/mac_change.py
index 010c395..c614e15 100644
--- a/client/tests/kvm/tests/mac_change.py
+++ b/client/tests/kvm/tests/mac_change.py
@@ -24,14 +24,11 @@ def run_mac_change(test, params, env):
         raise error.TestFail("Could not log into guest '%s'" % vm.name)
 
     old_mac = vm.get_mac_address(0)
-    new_different = False
-    while not new_different:
-        kvm_utils.free_mac_address(vm.root_dir, vm.instance, 0)
-        new_mac = kvm_utils.generate_mac_address(vm.root_dir,
-                                                 vm.instance,
-                                                 0, vm.mac_prefix)
+    while True:
+        vm.free_mac_address(0)
+        new_mac = kvm_utils.generate_mac_address(vm.instance, 0)
         if old_mac != new_mac:
-            new_different = True
+            break
     logging.info("The initial MAC address is %s", old_mac)
     interface = kvm_test_utils.get_linux_ifname(session, old_mac)
     # Start change MAC address
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [KVM-AUTOTEST PATCH 2/7] KVM test: VM.get_address(): fix handling of multiple NICs
  2010-10-24 11:01 [KVM-AUTOTEST PATCH 1/7] KVM test: simplify MAC address management Michael Goldish
@ 2010-10-24 11:01 ` Michael Goldish
  2010-10-24 11:01   ` [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method Michael Goldish
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Goldish @ 2010-10-24 11:01 UTC (permalink / raw)
  To: autotest, kvm

Use VM.get_mac_address() instead of kvm_utils.get_mac_ip_pair_from_dict().

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_vm.py |    6 +-----
 1 files changed, 1 insertions(+), 5 deletions(-)

diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index 51e7cfa..f3e803b 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -930,11 +930,7 @@ class VM:
                                   "%s" % mac)
                     return None
                 # Make sure the IP address is assigned to this guest
-                nic_dicts = [kvm_utils.get_sub_dict(self.params, nic)
-                             for nic in nics]
-                macs = [kvm_utils.get_mac_ip_pair_from_dict(dict)[0]
-                        for dict in nic_dicts]
-                macs.append(mac)
+                macs = [self.get_mac_address(i) for i in range(len(nics))]
                 if not kvm_utils.verify_ip_address_ownership(ip, macs):
                     logging.debug("Could not verify MAC-IP address mapping: "
                                   "%s ---> %s" % (mac, ip))
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method
  2010-10-24 11:01 ` [KVM-AUTOTEST PATCH 2/7] KVM test: VM.get_address(): fix handling of multiple NICs Michael Goldish
@ 2010-10-24 11:01   ` Michael Goldish
  2010-10-24 11:01     ` [KVM-AUTOTEST PATCH 4/7] KVM test: get_ifname(): use self.instance instead of self.vnc_port Michael Goldish
  2010-10-26 12:56     ` [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method Lucas Meneghel Rodrigues
  0 siblings, 2 replies; 9+ messages in thread
From: Michael Goldish @ 2010-10-24 11:01 UTC (permalink / raw)
  To: autotest, kvm

This patch removes all code related to the old manual method
(address_pools.cfg).

Note that now running in TAP mode requires an external DHCP server that accepts
*any* MAC address, because MAC addresses are randomly generated and cannot be
manually configured.

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_utils.py                      |  159 --------------------
 client/tests/kvm/kvm_vm.py                         |   34 ++---
 client/tests/kvm/tests/physical_resources_check.py |   11 +-
 client/tests/kvm/tests/stress_boot.py              |    3 -
 client/tests/kvm/tests_base.cfg.sample             |    2 -
 5 files changed, 16 insertions(+), 193 deletions(-)

diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py
index 778637d..f749f8d 100644
--- a/client/tests/kvm/kvm_utils.py
+++ b/client/tests/kvm/kvm_utils.py
@@ -203,165 +203,6 @@ def get_mac_address(vm_instance, nic_index):
     return mac
 
 
-def mac_str_to_int(addr):
-    """
-    Convert MAC address string to integer.
-
-    @param addr: String representing the MAC address.
-    """
-    return sum(int(s, 16) * 256 ** i
-               for i, s in enumerate(reversed(addr.split(":"))))
-
-
-def mac_int_to_str(addr):
-    """
-    Convert MAC address integer to string.
-
-    @param addr: Integer representing the MAC address.
-    """
-    return ":".join("%02x" % (addr >> 8 * i & 0xFF)
-                    for i in reversed(range(6)))
-
-
-def ip_str_to_int(addr):
-    """
-    Convert IP address string to integer.
-
-    @param addr: String representing the IP address.
-    """
-    return sum(int(s) * 256 ** i
-               for i, s in enumerate(reversed(addr.split("."))))
-
-
-def ip_int_to_str(addr):
-    """
-    Convert IP address integer to string.
-
-    @param addr: Integer representing the IP address.
-    """
-    return ".".join(str(addr >> 8 * i & 0xFF)
-                    for i in reversed(range(4)))
-
-
-def offset_mac(base, offset):
-    """
-    Add offset to a given MAC address.
-
-    @param base: String representing a MAC address.
-    @param offset: Offset to add to base (integer)
-    @return: A string representing the offset MAC address.
-    """
-    return mac_int_to_str(mac_str_to_int(base) + offset)
-
-
-def offset_ip(base, offset):
-    """
-    Add offset to a given IP address.
-
-    @param base: String representing an IP address.
-    @param offset: Offset to add to base (integer)
-    @return: A string representing the offset IP address.
-    """
-    return ip_int_to_str(ip_str_to_int(base) + offset)
-
-
-def get_mac_ip_pair_from_dict(dict):
-    """
-    Fetch a MAC-IP address pair from dict and return it.
-
-    The parameters in dict are expected to conform to a certain syntax.
-    Typical usage may be:
-
-    address_ranges = r1 r2 r3
-
-    address_range_base_mac_r1 = 55:44:33:22:11:00
-    address_range_base_ip_r1 = 10.0.0.0
-    address_range_size_r1 = 16
-
-    address_range_base_mac_r2 = 55:44:33:22:11:40
-    address_range_base_ip_r2 = 10.0.0.60
-    address_range_size_r2 = 25
-
-    address_range_base_mac_r3 = 55:44:33:22:12:10
-    address_range_base_ip_r3 = 10.0.1.20
-    address_range_size_r3 = 230
-
-    address_index = 0
-
-    All parameters except address_index specify a MAC-IP address pool.  The
-    pool consists of several MAC-IP address ranges.
-    address_index specified the index of the desired MAC-IP pair from the pool.
-
-    @param dict: The dictionary from which to fetch the addresses.
-    """
-    index = int(dict.get("address_index", 0))
-    for mac_range_name in get_sub_dict_names(dict, "address_ranges"):
-        mac_range_params = get_sub_dict(dict, mac_range_name)
-        mac_base = mac_range_params.get("address_range_base_mac")
-        ip_base = mac_range_params.get("address_range_base_ip")
-        size = int(mac_range_params.get("address_range_size", 1))
-        if index < size:
-            return (mac_base and offset_mac(mac_base, index),
-                    ip_base and offset_ip(ip_base, index))
-        index -= size
-    return (None, None)
-
-
-def get_sub_pool(dict, piece, num_pieces):
-    """
-    Split a MAC-IP pool and return a single requested piece.
-
-    For example, get_sub_pool(dict, 0, 3) will split the pool in 3 pieces and
-    return a dict representing the first piece.
-
-    @param dict: A dict that contains pool parameters.
-    @param piece: The index of the requested piece.  Should range from 0 to
-        num_pieces - 1.
-    @param num_pieces: The total number of pieces.
-    @return: A copy of dict, modified to describe the requested sub-pool.
-    """
-    range_dicts = [get_sub_dict(dict, name) for name in
-                   get_sub_dict_names(dict, "address_ranges")]
-    if not range_dicts:
-        return dict
-    ranges = [[d.get("address_range_base_mac"),
-               d.get("address_range_base_ip"),
-               int(d.get("address_range_size", 1))] for d in range_dicts]
-    total_size = sum(r[2] for r in ranges)
-    base = total_size * piece / num_pieces
-    size = total_size * (piece + 1) / num_pieces - base
-
-    # Find base of current sub-pool
-    for i in range(len(ranges)):
-        r = ranges[i]
-        if base < r[2]:
-            r[0] = r[0] and offset_mac(r[0], base)
-            r[1] = r[1] and offset_ip(r[1], base)
-            r[2] -= base
-            break
-        base -= r[2]
-
-    # Collect ranges up to end of current sub-pool
-    new_ranges = []
-    for i in range(i, len(ranges)):
-        r = ranges[i]
-        new_ranges.append(r)
-        if size <= r[2]:
-            r[2] = size
-            break
-        size -= r[2]
-
-    # Write new dict
-    new_dict = dict.copy()
-    new_dict["address_ranges"] = " ".join("r%d" % i for i in
-                                          range(len(new_ranges)))
-    for i in range(len(new_ranges)):
-        new_dict["address_range_base_mac_r%d" % i] = new_ranges[i][0]
-        new_dict["address_range_base_ip_r%d" % i] = new_ranges[i][1]
-        new_dict["address_range_size_r%d" % i] = new_ranges[i][2]
-    return new_dict
-
-
 def verify_ip_address_ownership(ip, macs, timeout=10.0):
     """
     Use arping and the ARP cache to make sure a given IP address belongs to one
diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index f3e803b..2db916f 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -920,21 +920,18 @@ class VM:
                 logging.debug("MAC address unavailable")
                 return None
             mac = mac.lower()
-            ip = None
-
-            if not ip or nic_params.get("always_use_tcpdump") == "yes":
-                # Get the IP address from the cache
-                ip = self.address_cache.get(mac)
-                if not ip:
-                    logging.debug("Could not find IP address for MAC address: "
-                                  "%s" % mac)
-                    return None
-                # Make sure the IP address is assigned to this guest
-                macs = [self.get_mac_address(i) for i in range(len(nics))]
-                if not kvm_utils.verify_ip_address_ownership(ip, macs):
-                    logging.debug("Could not verify MAC-IP address mapping: "
-                                  "%s ---> %s" % (mac, ip))
-                    return None
+            # Get the IP address from the cache
+            ip = self.address_cache.get(mac)
+            if not ip:
+                logging.debug("Could not find IP address for MAC address: %s" %
+                              mac)
+                return None
+            # Make sure the IP address is assigned to this guest
+            macs = [self.get_mac_address(i) for i in range(len(nics))]
+            if not kvm_utils.verify_ip_address_ownership(ip, macs):
+                logging.debug("Could not verify MAC-IP address mapping: "
+                              "%s ---> %s" % (mac, ip))
+                return None
             return ip
         else:
             return "localhost"
@@ -985,12 +982,7 @@ class VM:
 
         @param nic_index: Index of the NIC
         """
-        nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
-        nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
-        if nic_params.get("address_index"):
-            return kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
-        else:
-            return kvm_utils.get_mac_address(self.instance, nic_index)
+        return kvm_utils.get_mac_address(self.instance, nic_index)
 
 
     def free_mac_address(self, nic_index=0):
diff --git a/client/tests/kvm/tests/physical_resources_check.py b/client/tests/kvm/tests/physical_resources_check.py
index 6c8e154..682c7b2 100644
--- a/client/tests/kvm/tests/physical_resources_check.py
+++ b/client/tests/kvm/tests/physical_resources_check.py
@@ -123,14 +123,9 @@ def run_physical_resources_check(test, params, env):
     found_mac_addresses = re.findall("macaddr=(\S+)", o)
     logging.debug("Found MAC adresses: %s" % found_mac_addresses)
 
-    nic_index = 0
-    for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
-        nic_params = kvm_utils.get_sub_dict(params, nic_name)
-        if "address_index" in nic_params:
-            mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
-        else:
-            mac = vm.get_mac_address(nic_index)
-            nic_index += 1
+    num_nics = len(kvm_utils.get_sub_dict_names(params, "nics"))
+    for nic_index in range(num_nics):
+        mac = vm.get_mac_address(nic_index)
         if not string.lower(mac) in found_mac_addresses:
             n_fail += 1
             logging.error("MAC address mismatch:")
diff --git a/client/tests/kvm/tests/stress_boot.py b/client/tests/kvm/tests/stress_boot.py
index 0d3ed07..b7916b4 100644
--- a/client/tests/kvm/tests/stress_boot.py
+++ b/client/tests/kvm/tests/stress_boot.py
@@ -28,7 +28,6 @@ def run_stress_boot(tests, params, env):
 
     num = 2
     sessions = [session]
-    address_index = int(params.get("clone_address_index_base", 10))
 
     # boot the VMs
     while num <= int(params.get("max_vms")):
@@ -36,7 +35,6 @@ def run_stress_boot(tests, params, env):
             # clone vm according to the first one
             vm_name = "vm" + str(num)
             vm_params = vm.get_params().copy()
-            vm_params["address_index"] = str(address_index)
             curr_vm = vm.clone(vm_name, vm_params)
             kvm_utils.env_register_vm(env, vm_name, curr_vm)
             logging.info("Booting guest #%d" % num)
@@ -56,7 +54,6 @@ def run_stress_boot(tests, params, env):
                 if se.get_command_status(params.get("alive_test_cmd")) != 0:
                     raise error.TestFail("Session #%d is not responsive" % i)
             num += 1
-            address_index += 1
 
         except (error.TestFail, OSError):
             for se in sessions:
diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kvm/tests_base.cfg.sample
index 769d750..5bca544 100644
--- a/client/tests/kvm/tests_base.cfg.sample
+++ b/client/tests/kvm/tests_base.cfg.sample
@@ -54,7 +54,6 @@ guest_port_remote_shell = 22
 nic_mode = user
 #nic_mode = tap
 nic_script = scripts/qemu-ifup
-#address_index = 0
 run_tcpdump = yes
 
 # Misc
@@ -274,7 +273,6 @@ variants:
         type = stress_boot
         max_vms = 5    
         alive_test_cmd = uname -a
-        clone_address_index_base = 10
         login_timeout = 240
         kill_vm = yes
         kill_vm_vm1 = no
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [KVM-AUTOTEST PATCH 4/7] KVM test: get_ifname(): use self.instance instead of self.vnc_port
  2010-10-24 11:01   ` [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method Michael Goldish
@ 2010-10-24 11:01     ` Michael Goldish
  2010-10-24 11:01       ` [KVM-AUTOTEST PATCH 5/7] KVM test: kvm_monitor.py: replace MonitorSendError with MonitorSocketError Michael Goldish
  2010-10-26 12:56     ` [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method Lucas Meneghel Rodrigues
  1 sibling, 1 reply; 9+ messages in thread
From: Michael Goldish @ 2010-10-24 11:01 UTC (permalink / raw)
  To: autotest, kvm

The vnc_port attribute is only unique among VMs that use a VNC display.  Other
VMs don't bother to look for a free VNC port and don't occupy one, so vnc_port
can't be considered unique.  The last 11 characters of self.instance make up a
fairly unique string which can be used instead.  (The whole string can't be
used because it exceeds 15 characters.)

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_vm.py |    8 ++------
 1 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index 2db916f..a5c110c 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -959,10 +959,7 @@ class VM:
 
     def get_ifname(self, nic_index=0):
         """
-        Return the ifname of tap device for the guest nic.
-
-        The vnc_port is unique for each VM, nic_index is unique for each nic
-        of one VM, it can avoid repeated ifname.
+        Return the ifname of a tap device associated with a NIC.
 
         @param nic_index: Index of the NIC
         """
@@ -972,8 +969,7 @@ class VM:
         if nic_params.get("nic_ifname"):
             return nic_params.get("nic_ifname")
         else:
-            return "%s_%s_%s" % (nic_params.get("nic_model"),
-                                 nic_index, self.vnc_port)
+            return "t%d-%s" % (nic_index, self.instance[-11:])
 
 
     def get_mac_address(self, nic_index=0):
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [KVM-AUTOTEST PATCH 5/7] KVM test: kvm_monitor.py: replace MonitorSendError with MonitorSocketError
  2010-10-24 11:01     ` [KVM-AUTOTEST PATCH 4/7] KVM test: get_ifname(): use self.instance instead of self.vnc_port Michael Goldish
@ 2010-10-24 11:01       ` Michael Goldish
  2010-10-24 11:01         ` [KVM-AUTOTEST PATCH 6/7] KVM test: refactor migration code Michael Goldish
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Goldish @ 2010-10-24 11:01 UTC (permalink / raw)
  To: autotest, kvm; +Cc: Michael Goldish

- Replace MonitorSendError with MonitorSocketError.
- Embed socket.error messages in MonitorSocketError messages.
- Catch exceptions raised while receiving data (in addition to those raised
  while sending data).

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_monitor.py |   35 ++++++++++++++++++++---------------
 1 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/client/tests/kvm/kvm_monitor.py b/client/tests/kvm/kvm_monitor.py
index 7047850..e0365cd 100644
--- a/client/tests/kvm/kvm_monitor.py
+++ b/client/tests/kvm/kvm_monitor.py
@@ -21,7 +21,7 @@ class MonitorConnectError(MonitorError):
     pass
 
 
-class MonitorSendError(MonitorError):
+class MonitorSocketError(MonitorError):
     pass
 
 
@@ -111,7 +111,11 @@ class Monitor:
     def _recvall(self):
         s = ""
         while self._data_available():
-            data = self._socket.recv(1024)
+            try:
+                data = self._socket.recv(1024)
+            except socket.error, (errno, msg):
+                raise MonitorSocketError("Could not receive data from monitor "
+                                         "(%s)" % msg)
             if not data:
                 break
             s += data
@@ -164,7 +168,7 @@ class HumanMonitor(Monitor):
         s = ""
         end_time = time.time() + timeout
         while self._data_available(end_time - time.time()):
-            data = self._socket.recv(1024)
+            data = self._recvall()
             if not data:
                 break
             s += data
@@ -182,7 +186,7 @@ class HumanMonitor(Monitor):
 
         @param cmd: Command to send
         @raise MonitorLockError: Raised if the lock cannot be acquired
-        @raise MonitorSendError: Raised if the command cannot be sent
+        @raise MonitorSocketError: Raised if a socket error occurs
         """
         if not self._acquire_lock(20):
             raise MonitorLockError("Could not acquire exclusive lock to send "
@@ -191,9 +195,9 @@ class HumanMonitor(Monitor):
         try:
             try:
                 self._socket.sendall(cmd + "\n")
-            except socket.error:
-                raise MonitorSendError("Could not send monitor command '%s'" %
-                                       cmd)
+            except socket.error, (errno, msg):
+                raise MonitorSocketError("Could not send monitor command '%s' "
+                                         "(%s)" % (cmd, msg))
 
         finally:
             self._lock.release()
@@ -209,7 +213,7 @@ class HumanMonitor(Monitor):
         @param timeout: Time duration to wait for the (qemu) prompt to return
         @return: Output received from the monitor
         @raise MonitorLockError: Raised if the lock cannot be acquired
-        @raise MonitorSendError: Raised if the command cannot be sent
+        @raise MonitorSocketError: Raised if a socket error occurs
         @raise MonitorProtocolError: Raised if the (qemu) prompt cannot be
                 found after sending the command
         """
@@ -465,12 +469,13 @@ class QMPMonitor(Monitor):
         Send raw data without waiting for response.
 
         @param data: Data to send
-        @raise MonitorSendError: Raised if the data cannot be sent
+        @raise MonitorSocketError: Raised if a socket error occurs
         """
         try:
             self._socket.sendall(data)
-        except socket.error:
-            raise MonitorSendError("Could not send data: %r" % data)
+        except socket.error, (errno, msg):
+            raise MonitorSocketError("Could not send data: %r (%s)" %
+                                     (data, msg))
 
 
     def _get_response(self, id=None, timeout=20):
@@ -505,7 +510,7 @@ class QMPMonitor(Monitor):
         @param timeout: Time duration to wait for response
         @return: The response received
         @raise MonitorLockError: Raised if the lock cannot be acquired
-        @raise MonitorSendError: Raised if the command cannot be sent
+        @raise MonitorSocketError: Raised if a socket error occurs
         @raise MonitorProtocolError: Raised if no response is received
         @raise QMPCmdError: Raised if the response is an error message
                 (the exception's args are (cmd, args, data) where data is the
@@ -547,7 +552,7 @@ class QMPMonitor(Monitor):
         @param timeout: Time duration to wait for response
         @return: The response received
         @raise MonitorLockError: Raised if the lock cannot be acquired
-        @raise MonitorSendError: Raised if the command cannot be sent
+        @raise MonitorSocketError: Raised if a socket error occurs
         @raise MonitorProtocolError: Raised if no response is received
         """
         if not self._acquire_lock(20):
@@ -578,7 +583,7 @@ class QMPMonitor(Monitor):
         @param timeout: Time duration to wait for response
         @return: The response received
         @raise MonitorLockError: Raised if the lock cannot be acquired
-        @raise MonitorSendError: Raised if the command cannot be sent
+        @raise MonitorSocketError: Raised if a socket error occurs
         @raise MonitorProtocolError: Raised if no response is received
         """
         return self.cmd_raw(json.dumps(obj) + "\n")
@@ -597,7 +602,7 @@ class QMPMonitor(Monitor):
         @param timeout: Time duration to wait for response
         @return: The response received
         @raise MonitorLockError: Raised if the lock cannot be acquired
-        @raise MonitorSendError: Raised if the command cannot be sent
+        @raise MonitorSocketError: Raised if a socket error occurs
         @raise MonitorProtocolError: Raised if no response is received
         """
         return self.cmd_obj(self._build_cmd(cmd, args, id), timeout)
-- 
1.5.5.6


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [KVM-AUTOTEST PATCH 6/7] KVM test: refactor migration code
  2010-10-24 11:01       ` [KVM-AUTOTEST PATCH 5/7] KVM test: kvm_monitor.py: replace MonitorSendError with MonitorSocketError Michael Goldish
@ 2010-10-24 11:01         ` Michael Goldish
  2010-10-24 11:01           ` [KVM-AUTOTEST PATCH 7/7] [RFC] KVM test: migrate_cancel: allow for alternative spellings of 'cancelled' Michael Goldish
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Goldish @ 2010-10-24 11:01 UTC (permalink / raw)
  To: autotest, kvm; +Cc: Michael Goldish

- Refactor migration code so that the '-incoming ...' strings are hardcoded
  only in a single location (kvm_test_utils.py).
- Wrap the removal of the gzipped state file in a finally: clause.
- Get rid of the 'for_migration' and 'extra_params' parameters of VM.create()
  and introduce 'migration_mode' and 'migration_exec_cmd'
- Remove unix socket files in VM.destroy() because they are created by
  VM.create() (as opposed to gzipped state files which are created in
  kvm_test_utils.migrate())

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_preprocessing.py |   10 +--
 client/tests/kvm/kvm_test_utils.py    |  115 ++++++++++++++++-----------------
 client/tests/kvm/kvm_vm.py            |   44 ++++++------
 3 files changed, 80 insertions(+), 89 deletions(-)

diff --git a/client/tests/kvm/kvm_preprocessing.py b/client/tests/kvm/kvm_preprocessing.py
index e3de0b3..1ddf99b 100644
--- a/client/tests/kvm/kvm_preprocessing.py
+++ b/client/tests/kvm/kvm_preprocessing.py
@@ -59,14 +59,8 @@ def preprocess_vm(test, params, env, name):
         kvm_utils.env_register_vm(env, name, vm)
 
     start_vm = False
-    for_migration = False
 
-    if params.get("start_vm_for_migration") == "yes":
-        logging.debug("'start_vm_for_migration' specified; (re)starting VM "
-                      "with -incoming option...")
-        start_vm = True
-        for_migration = True
-    elif params.get("restart_vm") == "yes":
+    if params.get("restart_vm") == "yes":
         logging.debug("'restart_vm' specified; (re)starting VM...")
         start_vm = True
     elif params.get("start_vm") == "yes":
@@ -81,7 +75,7 @@ def preprocess_vm(test, params, env, name):
 
     if start_vm:
         # Start the VM (or restart it if it's already up)
-        if not vm.create(name, params, test.bindir, for_migration):
+        if not vm.create(name, params, test.bindir):
             raise error.TestError("Could not start VM")
     else:
         # Don't start the VM, just update its params
diff --git a/client/tests/kvm/kvm_test_utils.py b/client/tests/kvm/kvm_test_utils.py
index d9c5a6e..1bb8920 100644
--- a/client/tests/kvm/kvm_test_utils.py
+++ b/client/tests/kvm/kvm_test_utils.py
@@ -167,79 +167,76 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
             raise error.TestFail("Timeout expired while waiting for migration "
                                  "to finish")
 
+    dest_vm = vm.clone()
 
-    migration_file = os.path.join("/tmp/",
-                                  mig_protocol + time.strftime("%Y%m%d-%H%M%S"))
-    if mig_protocol == "tcp":
-        mig_extra_params = " -incoming tcp:0:%d"
-    elif mig_protocol == "unix":
-        mig_extra_params = " -incoming unix:%s"
-    elif mig_protocol == "exec":
+    if mig_protocol == "exec":
         # Exec is a little different from other migrate methods - first we
         # ask the monitor the migration, then the vm state is dumped to a
         # compressed file, then we start the dest vm with -incoming pointing
         # to it
-        mig_extra_params = " -incoming \"exec: gzip -c -d %s\"" % migration_file
-        uri = "\"exec:gzip -c > %s\"" % migration_file
-        vm.monitor.cmd("stop")
-        o = vm.monitor.migrate(uri)
-        wait_for_migration()
-
-    # Clone the source VM and ask the clone to wait for incoming migration
-    dest_vm = vm.clone()
-    if not dest_vm.create(extra_params=mig_extra_params, mac_source=vm):
-        raise error.TestError("Could not create dest VM")
-
-    try:
-        if mig_protocol == "tcp":
-            uri = "tcp:localhost:%d" % dest_vm.migration_port
-        elif mig_protocol == "unix":
-            uri = "unix:%s" % dest_vm.migration_file
+        try:
+            exec_file = "/tmp/exec-%s.gz" % kvm_utils.generate_random_string(8)
+            exec_cmd = "gzip -c -d %s" % exec_file
+            uri = '"exec:gzip -c > %s"' % exec_file
+            vm.monitor.cmd("stop")
+            vm.monitor.migrate(uri)
+            wait_for_migration()
 
-        if mig_protocol != "exec":
-            o = vm.monitor.migrate(uri)
+            if not dest_vm.create(migration_mode=mig_protocol,
+                                  migration_exec_cmd=exec_cmd, mac_source=vm):
+                raise error.TestError("Could not create dest VM")
+        finally:
+            logging.debug("Removing migration file %s", exec_file)
+            try:
+                os.remove(exec_file)
+            except OSError:
+                pass
+    else:
+        if not dest_vm.create(migration_mode=mig_protocol, mac_source=vm):
+            raise error.TestError("Could not create dest VM")
+        try:
+            if mig_protocol == "tcp":
+                uri = "tcp:localhost:%d" % dest_vm.migration_port
+            elif mig_protocol == "unix":
+                uri = "unix:%s" % dest_vm.migration_file
+            vm.monitor.migrate(uri)
 
-            if mig_protocol == "tcp" and mig_cancel:
+            if mig_cancel:
                 time.sleep(2)
-                o = vm.monitor.cmd("migrate_cancel")
+                vm.monitor.cmd("migrate_cancel")
                 if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2,
-                                          "Waiting for migration cancel"):
-                    raise error.TestFail("Fail to cancel migration")
+                                          "Waiting for migration "
+                                          "cancellation"):
+                    raise error.TestFail("Failed to cancel migration")
                 dest_vm.destroy(gracefully=False)
                 return vm
+            else:
+                wait_for_migration()
+        except:
+            dest_vm.destroy()
+            raise
+
+    # Report migration status
+    if mig_succeeded():
+        logging.info("Migration finished successfully")
+    elif mig_failed():
+        raise error.TestFail("Migration failed")
+    else:
+        raise error.TestFail("Migration ended with unknown status")
 
-            wait_for_migration()
-
-        # Report migration status
-        if mig_succeeded():
-            logging.info("Migration finished successfully")
-        elif mig_failed():
-            raise error.TestFail("Migration failed")
-        else:
-            raise error.TestFail("Migration ended with unknown status")
-
-        o = dest_vm.monitor.info("status")
-        if "paused" in o:
-            logging.debug("Destination VM is paused, resuming it...")
-            dest_vm.monitor.cmd("cont")
-
-        if os.path.exists(migration_file):
-            logging.debug("Removing migration file %s", migration_file)
-            os.remove(migration_file)
-
-        # Kill the source VM
-        vm.destroy(gracefully=False)
+    if "paused" in dest_vm.monitor.info("status"):
+        logging.debug("Destination VM is paused, resuming it...")
+        dest_vm.monitor.cmd("cont")
 
-        # Replace the source VM with the new cloned VM
-        if env is not None:
-            kvm_utils.env_register_vm(env, vm.name, dest_vm)
+    # Kill the source VM
+    vm.destroy(gracefully=False)
 
-        # Return the new cloned VM
-        return dest_vm
+    # Replace the source VM with the new cloned VM
+    if env is not None:
+        kvm_utils.env_register_vm(env, vm.name, dest_vm)
 
-    except:
-        dest_vm.destroy()
-        raise
+    # Return the new cloned VM
+    return dest_vm
 
 
 def get_time(session, time_command, time_filter_re, time_format):
diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index a5c110c..a860437 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -507,23 +507,20 @@ class VM:
         return qemu_cmd
 
 
-    def create(self, name=None, params=None, root_dir=None,
-               for_migration=False, timeout=5.0, extra_params=None,
-               mac_source=None):
+    def create(self, name=None, params=None, root_dir=None, timeout=5.0,
+               migration_mode=None, migration_exec_cmd=None, mac_source=None):
         """
         Start the VM by running a qemu command.
-        All parameters are optional. The following applies to all parameters
-        but for_migration: If a parameter is not supplied, the corresponding
-        value stored in the class attributes is used, and if it is supplied,
-        it is stored for later use.
+        All parameters are optional. If name, params or root_dir are not
+        supplied, the respective values stored as class attributes are used.
 
         @param name: The name of the object
         @param params: A dict containing VM params
         @param root_dir: Base directory for relative filenames
-        @param for_migration: If True, start the VM with the -incoming
-        option
-        @param extra_params: extra params for qemu command.e.g -incoming option
-        Please use this parameter instead of for_migration.
+        @param migration_mode: If supplied, start VM for incoming migration
+                using this protocol (either 'tcp', 'unix' or 'exec')
+        @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."'
+                (e.g. 'gzip -c -d filename') if migration_mode is 'exec'
         @param mac_source: A VM object from which to copy MAC addresses. If not
                 specified, new addresses will be generated.
         """
@@ -655,17 +652,15 @@ class VM:
             # Make qemu command
             qemu_command = self.make_qemu_command()
 
-            # Enable migration support for VM by adding extra_params.
-            if extra_params is not None:
-                if " -incoming tcp:0:%d" == extra_params:
-                    self.migration_port = kvm_utils.find_free_port(5200, 6000)
-                    qemu_command += extra_params % self.migration_port
-                elif " -incoming unix:%s" == extra_params:
-                    self.migration_file = os.path.join("/tmp/", "unix-" +
-                                          time.strftime("%Y%m%d-%H%M%S"))
-                    qemu_command += extra_params % self.migration_file
-                else:
-                    qemu_command += extra_params
+            # Add migration parameters if required
+            if migration_mode == "tcp":
+                self.migration_port = kvm_utils.find_free_port(5200, 6000)
+                qemu_command += " -incoming tcp:0:%d" % self.migration_port
+            elif migration_mode == "unix":
+                self.migration_file = "/tmp/migration-unix-%s" % self.instance
+                qemu_command += " -incoming unix:%s" % self.migration_file
+            elif migration_mode == "exec":
+                qemu_command += ' -incoming "exec:%s"' % migration_exec_cmd
 
             logging.debug("Running qemu command:\n%s", qemu_command)
             self.process = kvm_subprocess.run_bg(qemu_command, None,
@@ -826,6 +821,11 @@ class VM:
                     os.unlink(f)
                 except OSError:
                     pass
+            if hasattr(self, "migration_file"):
+                try:
+                    os.unlink(self.migration_file)
+                except OSError:
+                    pass
             num_nics = len(kvm_utils.get_sub_dict_names(self.params, "nics"))
             for vlan in range(num_nics):
                 self.free_mac_address(vlan)
-- 
1.5.5.6


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [KVM-AUTOTEST PATCH 7/7] [RFC] KVM test: migrate_cancel: allow for alternative spellings of 'cancelled'
  2010-10-24 11:01         ` [KVM-AUTOTEST PATCH 6/7] KVM test: refactor migration code Michael Goldish
@ 2010-10-24 11:01           ` Michael Goldish
  2010-10-26 13:08             ` Lucas Meneghel Rodrigues
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Goldish @ 2010-10-24 11:01 UTC (permalink / raw)
  To: autotest, kvm

Is there any chance someone will decide to switch over to the American spelling?

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_test_utils.py |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/client/tests/kvm/kvm_test_utils.py b/client/tests/kvm/kvm_test_utils.py
index 1bb8920..a3b182b 100644
--- a/client/tests/kvm/kvm_test_utils.py
+++ b/client/tests/kvm/kvm_test_utils.py
@@ -157,9 +157,11 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
     def mig_cancelled():
         o = vm.monitor.info("migrate")
         if isinstance(o, str):
-            return "Migration status: cancelled" in o
+            return ("Migration status: cancelled" in o or
+                    "Migration status: canceled" in o)
         else:
-            return o.get("status") == "cancelled"
+            return (o.get("status") == "cancelled" or
+                    o.get("status") == "canceled")
 
     def wait_for_migration():
         if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method
  2010-10-24 11:01   ` [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method Michael Goldish
  2010-10-24 11:01     ` [KVM-AUTOTEST PATCH 4/7] KVM test: get_ifname(): use self.instance instead of self.vnc_port Michael Goldish
@ 2010-10-26 12:56     ` Lucas Meneghel Rodrigues
  1 sibling, 0 replies; 9+ messages in thread
From: Lucas Meneghel Rodrigues @ 2010-10-26 12:56 UTC (permalink / raw)
  To: Michael Goldish; +Cc: autotest, kvm

On Sun, 2010-10-24 at 13:01 +0200, Michael Goldish wrote:
> This patch removes all code related to the old manual method
> (address_pools.cfg).
> 
> Note that now running in TAP mode requires an external DHCP server that accepts
> *any* MAC address, because MAC addresses are randomly generated and cannot be
> manually configured.

Yes, this patch looks good. I don't think there are much DHCP servers
that do not accept any MAC address. It might be good to document this
information on the wiki though.

> Signed-off-by: Michael Goldish <mgoldish@redhat.com>
> ---
>  client/tests/kvm/kvm_utils.py                      |  159 --------------------
>  client/tests/kvm/kvm_vm.py                         |   34 ++---
>  client/tests/kvm/tests/physical_resources_check.py |   11 +-
>  client/tests/kvm/tests/stress_boot.py              |    3 -
>  client/tests/kvm/tests_base.cfg.sample             |    2 -
>  5 files changed, 16 insertions(+), 193 deletions(-)
> 
> diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py
> index 778637d..f749f8d 100644
> --- a/client/tests/kvm/kvm_utils.py
> +++ b/client/tests/kvm/kvm_utils.py
> @@ -203,165 +203,6 @@ def get_mac_address(vm_instance, nic_index):
>      return mac
>  
> 
> -def mac_str_to_int(addr):
> -    """
> -    Convert MAC address string to integer.
> -
> -    @param addr: String representing the MAC address.
> -    """
> -    return sum(int(s, 16) * 256 ** i
> -               for i, s in enumerate(reversed(addr.split(":"))))
> -
> -
> -def mac_int_to_str(addr):
> -    """
> -    Convert MAC address integer to string.
> -
> -    @param addr: Integer representing the MAC address.
> -    """
> -    return ":".join("%02x" % (addr >> 8 * i & 0xFF)
> -                    for i in reversed(range(6)))
> -
> -
> -def ip_str_to_int(addr):
> -    """
> -    Convert IP address string to integer.
> -
> -    @param addr: String representing the IP address.
> -    """
> -    return sum(int(s) * 256 ** i
> -               for i, s in enumerate(reversed(addr.split("."))))
> -
> -
> -def ip_int_to_str(addr):
> -    """
> -    Convert IP address integer to string.
> -
> -    @param addr: Integer representing the IP address.
> -    """
> -    return ".".join(str(addr >> 8 * i & 0xFF)
> -                    for i in reversed(range(4)))
> -
> -
> -def offset_mac(base, offset):
> -    """
> -    Add offset to a given MAC address.
> -
> -    @param base: String representing a MAC address.
> -    @param offset: Offset to add to base (integer)
> -    @return: A string representing the offset MAC address.
> -    """
> -    return mac_int_to_str(mac_str_to_int(base) + offset)
> -
> -
> -def offset_ip(base, offset):
> -    """
> -    Add offset to a given IP address.
> -
> -    @param base: String representing an IP address.
> -    @param offset: Offset to add to base (integer)
> -    @return: A string representing the offset IP address.
> -    """
> -    return ip_int_to_str(ip_str_to_int(base) + offset)
> -
> -
> -def get_mac_ip_pair_from_dict(dict):
> -    """
> -    Fetch a MAC-IP address pair from dict and return it.
> -
> -    The parameters in dict are expected to conform to a certain syntax.
> -    Typical usage may be:
> -
> -    address_ranges = r1 r2 r3
> -
> -    address_range_base_mac_r1 = 55:44:33:22:11:00
> -    address_range_base_ip_r1 = 10.0.0.0
> -    address_range_size_r1 = 16
> -
> -    address_range_base_mac_r2 = 55:44:33:22:11:40
> -    address_range_base_ip_r2 = 10.0.0.60
> -    address_range_size_r2 = 25
> -
> -    address_range_base_mac_r3 = 55:44:33:22:12:10
> -    address_range_base_ip_r3 = 10.0.1.20
> -    address_range_size_r3 = 230
> -
> -    address_index = 0
> -
> -    All parameters except address_index specify a MAC-IP address pool.  The
> -    pool consists of several MAC-IP address ranges.
> -    address_index specified the index of the desired MAC-IP pair from the pool.
> -
> -    @param dict: The dictionary from which to fetch the addresses.
> -    """
> -    index = int(dict.get("address_index", 0))
> -    for mac_range_name in get_sub_dict_names(dict, "address_ranges"):
> -        mac_range_params = get_sub_dict(dict, mac_range_name)
> -        mac_base = mac_range_params.get("address_range_base_mac")
> -        ip_base = mac_range_params.get("address_range_base_ip")
> -        size = int(mac_range_params.get("address_range_size", 1))
> -        if index < size:
> -            return (mac_base and offset_mac(mac_base, index),
> -                    ip_base and offset_ip(ip_base, index))
> -        index -= size
> -    return (None, None)
> -
> -
> -def get_sub_pool(dict, piece, num_pieces):
> -    """
> -    Split a MAC-IP pool and return a single requested piece.
> -
> -    For example, get_sub_pool(dict, 0, 3) will split the pool in 3 pieces and
> -    return a dict representing the first piece.
> -
> -    @param dict: A dict that contains pool parameters.
> -    @param piece: The index of the requested piece.  Should range from 0 to
> -        num_pieces - 1.
> -    @param num_pieces: The total number of pieces.
> -    @return: A copy of dict, modified to describe the requested sub-pool.
> -    """
> -    range_dicts = [get_sub_dict(dict, name) for name in
> -                   get_sub_dict_names(dict, "address_ranges")]
> -    if not range_dicts:
> -        return dict
> -    ranges = [[d.get("address_range_base_mac"),
> -               d.get("address_range_base_ip"),
> -               int(d.get("address_range_size", 1))] for d in range_dicts]
> -    total_size = sum(r[2] for r in ranges)
> -    base = total_size * piece / num_pieces
> -    size = total_size * (piece + 1) / num_pieces - base
> -
> -    # Find base of current sub-pool
> -    for i in range(len(ranges)):
> -        r = ranges[i]
> -        if base < r[2]:
> -            r[0] = r[0] and offset_mac(r[0], base)
> -            r[1] = r[1] and offset_ip(r[1], base)
> -            r[2] -= base
> -            break
> -        base -= r[2]
> -
> -    # Collect ranges up to end of current sub-pool
> -    new_ranges = []
> -    for i in range(i, len(ranges)):
> -        r = ranges[i]
> -        new_ranges.append(r)
> -        if size <= r[2]:
> -            r[2] = size
> -            break
> -        size -= r[2]
> -
> -    # Write new dict
> -    new_dict = dict.copy()
> -    new_dict["address_ranges"] = " ".join("r%d" % i for i in
> -                                          range(len(new_ranges)))
> -    for i in range(len(new_ranges)):
> -        new_dict["address_range_base_mac_r%d" % i] = new_ranges[i][0]
> -        new_dict["address_range_base_ip_r%d" % i] = new_ranges[i][1]
> -        new_dict["address_range_size_r%d" % i] = new_ranges[i][2]
> -    return new_dict
> -
> -
>  def verify_ip_address_ownership(ip, macs, timeout=10.0):
>      """
>      Use arping and the ARP cache to make sure a given IP address belongs to one
> diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
> index f3e803b..2db916f 100755
> --- a/client/tests/kvm/kvm_vm.py
> +++ b/client/tests/kvm/kvm_vm.py
> @@ -920,21 +920,18 @@ class VM:
>                  logging.debug("MAC address unavailable")
>                  return None
>              mac = mac.lower()
> -            ip = None
> -
> -            if not ip or nic_params.get("always_use_tcpdump") == "yes":
> -                # Get the IP address from the cache
> -                ip = self.address_cache.get(mac)
> -                if not ip:
> -                    logging.debug("Could not find IP address for MAC address: "
> -                                  "%s" % mac)
> -                    return None
> -                # Make sure the IP address is assigned to this guest
> -                macs = [self.get_mac_address(i) for i in range(len(nics))]
> -                if not kvm_utils.verify_ip_address_ownership(ip, macs):
> -                    logging.debug("Could not verify MAC-IP address mapping: "
> -                                  "%s ---> %s" % (mac, ip))
> -                    return None
> +            # Get the IP address from the cache
> +            ip = self.address_cache.get(mac)
> +            if not ip:
> +                logging.debug("Could not find IP address for MAC address: %s" %
> +                              mac)
> +                return None
> +            # Make sure the IP address is assigned to this guest
> +            macs = [self.get_mac_address(i) for i in range(len(nics))]
> +            if not kvm_utils.verify_ip_address_ownership(ip, macs):
> +                logging.debug("Could not verify MAC-IP address mapping: "
> +                              "%s ---> %s" % (mac, ip))
> +                return None
>              return ip
>          else:
>              return "localhost"
> @@ -985,12 +982,7 @@ class VM:
>  
>          @param nic_index: Index of the NIC
>          """
> -        nic_name = kvm_utils.get_sub_dict_names(self.params, "nics")[nic_index]
> -        nic_params = kvm_utils.get_sub_dict(self.params, nic_name)
> -        if nic_params.get("address_index"):
> -            return kvm_utils.get_mac_ip_pair_from_dict(nic_params)[0]
> -        else:
> -            return kvm_utils.get_mac_address(self.instance, nic_index)
> +        return kvm_utils.get_mac_address(self.instance, nic_index)
>  
> 
>      def free_mac_address(self, nic_index=0):
> diff --git a/client/tests/kvm/tests/physical_resources_check.py b/client/tests/kvm/tests/physical_resources_check.py
> index 6c8e154..682c7b2 100644
> --- a/client/tests/kvm/tests/physical_resources_check.py
> +++ b/client/tests/kvm/tests/physical_resources_check.py
> @@ -123,14 +123,9 @@ def run_physical_resources_check(test, params, env):
>      found_mac_addresses = re.findall("macaddr=(\S+)", o)
>      logging.debug("Found MAC adresses: %s" % found_mac_addresses)
>  
> -    nic_index = 0
> -    for nic_name in kvm_utils.get_sub_dict_names(params, "nics"):
> -        nic_params = kvm_utils.get_sub_dict(params, nic_name)
> -        if "address_index" in nic_params:
> -            mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params)
> -        else:
> -            mac = vm.get_mac_address(nic_index)
> -            nic_index += 1
> +    num_nics = len(kvm_utils.get_sub_dict_names(params, "nics"))
> +    for nic_index in range(num_nics):
> +        mac = vm.get_mac_address(nic_index)
>          if not string.lower(mac) in found_mac_addresses:
>              n_fail += 1
>              logging.error("MAC address mismatch:")
> diff --git a/client/tests/kvm/tests/stress_boot.py b/client/tests/kvm/tests/stress_boot.py
> index 0d3ed07..b7916b4 100644
> --- a/client/tests/kvm/tests/stress_boot.py
> +++ b/client/tests/kvm/tests/stress_boot.py
> @@ -28,7 +28,6 @@ def run_stress_boot(tests, params, env):
>  
>      num = 2
>      sessions = [session]
> -    address_index = int(params.get("clone_address_index_base", 10))
>  
>      # boot the VMs
>      while num <= int(params.get("max_vms")):
> @@ -36,7 +35,6 @@ def run_stress_boot(tests, params, env):
>              # clone vm according to the first one
>              vm_name = "vm" + str(num)
>              vm_params = vm.get_params().copy()
> -            vm_params["address_index"] = str(address_index)
>              curr_vm = vm.clone(vm_name, vm_params)
>              kvm_utils.env_register_vm(env, vm_name, curr_vm)
>              logging.info("Booting guest #%d" % num)
> @@ -56,7 +54,6 @@ def run_stress_boot(tests, params, env):
>                  if se.get_command_status(params.get("alive_test_cmd")) != 0:
>                      raise error.TestFail("Session #%d is not responsive" % i)
>              num += 1
> -            address_index += 1
>  
>          except (error.TestFail, OSError):
>              for se in sessions:
> diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kvm/tests_base.cfg.sample
> index 769d750..5bca544 100644
> --- a/client/tests/kvm/tests_base.cfg.sample
> +++ b/client/tests/kvm/tests_base.cfg.sample
> @@ -54,7 +54,6 @@ guest_port_remote_shell = 22
>  nic_mode = user
>  #nic_mode = tap
>  nic_script = scripts/qemu-ifup
> -#address_index = 0
>  run_tcpdump = yes
>  
>  # Misc
> @@ -274,7 +273,6 @@ variants:
>          type = stress_boot
>          max_vms = 5    
>          alive_test_cmd = uname -a
> -        clone_address_index_base = 10
>          login_timeout = 240
>          kill_vm = yes
>          kill_vm_vm1 = no

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [KVM-AUTOTEST PATCH 7/7] [RFC] KVM test: migrate_cancel: allow for alternative spellings of 'cancelled'
  2010-10-24 11:01           ` [KVM-AUTOTEST PATCH 7/7] [RFC] KVM test: migrate_cancel: allow for alternative spellings of 'cancelled' Michael Goldish
@ 2010-10-26 13:08             ` Lucas Meneghel Rodrigues
  0 siblings, 0 replies; 9+ messages in thread
From: Lucas Meneghel Rodrigues @ 2010-10-26 13:08 UTC (permalink / raw)
  To: Michael Goldish; +Cc: autotest, kvm

On Sun, 2010-10-24 at 13:01 +0200, Michael Goldish wrote:
> Is there any chance someone will decide to switch over to the American spelling?

This is mainly harmless. Even if the switch won't happen, this is
absolutely fine, thanks!

> Signed-off-by: Michael Goldish <mgoldish@redhat.com>
> ---
>  client/tests/kvm/kvm_test_utils.py |    6 ++++--
>  1 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/client/tests/kvm/kvm_test_utils.py b/client/tests/kvm/kvm_test_utils.py
> index 1bb8920..a3b182b 100644
> --- a/client/tests/kvm/kvm_test_utils.py
> +++ b/client/tests/kvm/kvm_test_utils.py
> @@ -157,9 +157,11 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
>      def mig_cancelled():
>          o = vm.monitor.info("migrate")
>          if isinstance(o, str):
> -            return "Migration status: cancelled" in o
> +            return ("Migration status: cancelled" in o or
> +                    "Migration status: canceled" in o)
>          else:
> -            return o.get("status") == "cancelled"
> +            return (o.get("status") == "cancelled" or
> +                    o.get("status") == "canceled")
>  
>      def wait_for_migration():
>          if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2010-10-26 13:08 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-24 11:01 [KVM-AUTOTEST PATCH 1/7] KVM test: simplify MAC address management Michael Goldish
2010-10-24 11:01 ` [KVM-AUTOTEST PATCH 2/7] KVM test: VM.get_address(): fix handling of multiple NICs Michael Goldish
2010-10-24 11:01   ` [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method Michael Goldish
2010-10-24 11:01     ` [KVM-AUTOTEST PATCH 4/7] KVM test: get_ifname(): use self.instance instead of self.vnc_port Michael Goldish
2010-10-24 11:01       ` [KVM-AUTOTEST PATCH 5/7] KVM test: kvm_monitor.py: replace MonitorSendError with MonitorSocketError Michael Goldish
2010-10-24 11:01         ` [KVM-AUTOTEST PATCH 6/7] KVM test: refactor migration code Michael Goldish
2010-10-24 11:01           ` [KVM-AUTOTEST PATCH 7/7] [RFC] KVM test: migrate_cancel: allow for alternative spellings of 'cancelled' Michael Goldish
2010-10-26 13:08             ` Lucas Meneghel Rodrigues
2010-10-26 12:56     ` [KVM-AUTOTEST PATCH 3/7] [RFC] KVM test: remove all code related to the old MAC address pool method Lucas Meneghel Rodrigues

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.